- feat(domain): Hashtag value object with canonical extract() — unifies two
divergent private implementations; fields pre-compute raw/normalized/url_slug/ap_name
- feat(presentation): Deps<S: FromAppState> extractor — each handler now
declares its exact dependency surface; AppState unchanged; handlers
become unit-testable without mocking all 20 deps
- refactor(feed): replace 5 flat FeedRepository methods with FeedQuery/FeedScope
— single query() method; SQL shared logic lives once; adding feed types
no longer requires 5 edits
- refactor(activitypub): ActivityPubRepository + OutboundFederationPort moved
out of domain::ports into activitypub-base::ap_ports — domain crate no
longer knows about AP IDs, inboxes, or actor URLs
- fix(outbox): OutboxRelay now opens a per-row transaction so FOR UPDATE
SKIP LOCKED actually holds the lock during publish + mark_delivered