Fix per-app AP delivery, NULL uniqueness, and reverse discovery

- Delivery handler now signs/delivers using the per-app domain that
  matches the follower's subscription (not always federation domain)
- app_domain is NOT NULL with default 'federation' (sentinel replaces
  NULL to avoid uniqueness constraint edge case)
- Aggregate actor advertises per-app actors via alsoKnownAs
- Migration backfills existing NULL rows to 'federation'

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
giles
2026-02-23 19:25:24 +00:00
parent f2262f702b
commit 1bb19c96ed
9 changed files with 117 additions and 80 deletions

View File

@@ -129,8 +129,9 @@ class APActivity(Base):
class APFollower(Base):
"""A remote follower of a local actor.
``app_domain`` scopes the follow to a specific app (e.g. "blog").
NULL means the follower subscribes to the aggregate (all activities).
``app_domain`` scopes the follow to a specific app (e.g. "blog",
"market", "events"). "federation" means the aggregate — the
follower subscribes to all activities.
"""
__tablename__ = "ap_followers"
@@ -142,7 +143,9 @@ class APFollower(Base):
follower_inbox: Mapped[str] = mapped_column(String(512), nullable=False)
follower_actor_url: Mapped[str] = mapped_column(String(512), nullable=False)
follower_public_key: Mapped[str | None] = mapped_column(Text, nullable=True)
app_domain: Mapped[str | None] = mapped_column(String(64), nullable=True)
app_domain: Mapped[str] = mapped_column(
String(64), nullable=False, default="federation", server_default="federation",
)
created_at: Mapped[datetime] = mapped_column(
DateTime(timezone=True), nullable=False, server_default=func.now(),
)