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.
Align richtext facet lexicon with atProto Lexinomicon style guide:
- Remove $type from required fields (automatically added by SDK for union discrimination)
- Remove handle field from mention type (use persistent DIDs only per best practices)
- Add maxGraphemes constraint to spoiler reason field for proper internationalization
- Update descriptions to match Bluesky documentation patterns
- Update tests to remove handle field references
References: https://github.com/bluesky-social/atproto/discussions/4245
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Fixes test failures caused by hardcoded community names that created
duplicate handle conflicts across test runs.
Changed:
- update-test → update-test-{timestamp}
- sub-test → sub-test-{timestamp}
- delete-test → delete-test-{timestamp}
All consumer tests now pass consistently.
This commit addresses all critical and important issues from the PR review:
## Critical Issues Fixed
1. **Removed fallback to deterministic handle construction**
- Production now ONLY resolves handles from PLC (source of truth)
- If PLC resolution fails, indexing fails with error (no fallback)
- Prevents creating communities with incorrect handles in federated scenarios
- Test mode (nil resolver) still uses deterministic construction for testing
2. **Deleted unnecessary migration 016**
- Migration only updated column comment (no schema change)
- Documentation now lives in code comments instead
- Keeps migration history focused on actual schema changes
## Important Issues Fixed
3. **Extracted duplicated handle construction to helper function**
- Created `constructHandleFromProfile()` helper
- Validates hostedBy format (must be did:web)
- Returns empty string if invalid, triggering repository validation
- DRY principle now followed
4. **Added repository validation for empty handles**
- Repository now fails fast if consumer tries to insert empty handle
- Makes contract explicit: "handle is required (should be constructed by consumer)"
- Prevents silent failures
5. **Fixed E2E test to remove did/handle from record data**
- Removed 'did' and 'handle' fields from test record
- Added missing 'owner' field
- Test now accurately reflects real-world PDS records (atProto compliant)
6. **Added comprehensive PLC resolution integration tests**
- Created mock identity resolver for testing
- Test: Successfully resolves handle from PLC
- Test: Fails when PLC resolution fails (verifies no fallback)
- Test: Validates invalid hostedBy format in test mode
- All tests verify the production code path
## Test Strategy Improvements
7. **Updated all consumer tests to use mock resolver**
- Tests now exercise production PLC resolution code path
- Mock resolver pre-configured with DID → handle mappings
- Only one test uses nil resolver (validates edge case)
- E2E test uses real identity resolver with local PLC
8. **Added setupIdentityResolver() helper for test infrastructure**
- Reusable helper for configuring PLC resolution in tests
- Uses local PLC at http://localhost:3002 for E2E tests
- Production-like testing without external dependencies
## Architecture Summary
**Production flow:**
Record (no handle) → PLC lookup → Handle from PLC → Cache in DB
↓ (if fails)
Error + backfill later
**Test flow with mock:**
Record (no handle) → Mock PLC lookup → Pre-configured handle → Cache in DB
**Test mode (nil resolver):**
Record (no handle) → Deterministic construction → Validate format → Cache in DB
All tests pass. Server builds successfully.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Following atProto best practices, community profile records now only contain
user-controlled data. Handles are mutable and resolved from DIDs via PLC, so
they should not be stored in immutable records. Member/subscriber counts are
AppView-computed stats, not record data.
Changes:
- Remove 'handle' field from community profile record creation
- Remove 'handle' field from community profile record updates
- Remove 'memberCount' and 'subscriberCount' from profile records
- Update E2E test to not expect handle in PDS record
- Update consumer test mock data to match new record schema
AppView caching (Go structs) still maintains these fields for performance:
- service.go:190 - Community struct keeps Handle field
- community_consumer.go:159,241 - Consumer reads handle for caching
This matches Bluesky's app.bsky.actor.profile pattern where handles are
resolved from DIDs, not stored in profile records.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Update cross-reference tests to use new defs locations
- Remove handle field from actor profile test data
- Update invalid test case to check for missing createdAt instead of handle
- Clean up test data for removed lexicons (block, saved, preferences)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Actor changes:
- Remove handle from actor.profile record (resolved from DID, not stored)
- Remove geoLocation from actor.profile (not implemented)
- Remove verification fields from profile (AppView concern, not record data)
- Remove federation fields from profile (AppView concern, not record data)
- Remove moderation fields from profile (AppView concern, not record data)
- Update actor.getProfile to return profileViewDetailed from defs
- Update actor.updateProfile to remove geoLocation reference
Community changes:
- Remove handle from community.profile record (resolved from DID, not stored)
- Remove memberCount, subscriberCount from record (AppView cached stats)
- Remove federatedFrom, federatedId from record (AppView metadata)
- Remove federation and contentRules from record (not implemented)
- Update community.get to return communityViewDetailed from defs
- Update community.list to return communityView array from defs
Key principle: Records contain only user-controlled data. Computed stats,
cached values, and viewer state live in AppView views (defs.json), not records.
Following atProto best practices per:
https://github.com/bluesky-social/atproto/discussions/4245
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>