Backfill only current posts: skip deleted, use latest update data

Previously backfill_follower sent all Create activities regardless
of whether they were later Deleted or Updated. Now it excludes
deleted sources and applies the latest Update's object_data so
new followers see the current version of each post.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
giles
2026-02-23 21:36:30 +00:00
parent dd9cb9f5f2
commit 61ad2db2f3

View File

@@ -101,7 +101,11 @@ async def backfill_follower(
domain: str,
origin_app: str | None = None,
) -> None:
"""Deliver recent Create activities to a new follower's inbox."""
"""Deliver recent *current* Create activities to a new follower's inbox.
Skips Creates whose source was later Deleted, and uses the latest
Update data when available (so the follower sees the current version).
"""
from shared.events.handlers.ap_delivery_handler import (
_build_activity_json, _deliver_to_inbox,
)
@@ -110,18 +114,68 @@ async def backfill_follower(
APActivity.actor_profile_id == actor.id,
APActivity.is_local == True, # noqa: E712
APActivity.activity_type == "Create",
APActivity.source_type.isnot(None),
APActivity.source_id.isnot(None),
]
if origin_app is not None:
filters.append(APActivity.origin_app == origin_app)
activities = (
creates = (
await session.execute(
select(APActivity).where(*filters)
.order_by(APActivity.published.desc())
.limit(20)
.limit(40)
)
).scalars().all()
if not creates:
return
# Collect source keys that have been Deleted
source_keys = {(c.source_type, c.source_id) for c in creates}
deleted_keys: set[tuple[str | None, int | None]] = set()
if source_keys:
deletes = (
await session.execute(
select(APActivity.source_type, APActivity.source_id).where(
APActivity.actor_profile_id == actor.id,
APActivity.activity_type == "Delete",
APActivity.is_local == True, # noqa: E712
)
)
).all()
deleted_keys = {(d[0], d[1]) for d in deletes}
# For sources with Updates, grab the latest Update's object_data
updated_data: dict[tuple[str | None, int | None], dict] = {}
if source_keys:
updates = (
await session.execute(
select(APActivity).where(
APActivity.actor_profile_id == actor.id,
APActivity.activity_type == "Update",
APActivity.is_local == True, # noqa: E712
).order_by(APActivity.published.desc())
)
).scalars().all()
for u in updates:
key = (u.source_type, u.source_id)
if key not in updated_data and key in source_keys:
updated_data[key] = u.object_data or {}
# Filter to current, non-deleted Creates (limit 20)
activities = []
for c in creates:
key = (c.source_type, c.source_id)
if key in deleted_keys:
continue
# Apply latest Update data if available
if key in updated_data:
c.object_data = updated_data[key]
activities.append(c)
if len(activities) >= 20:
break
if not activities:
return