Older data stores emoji reactions as EmojiReaction. The per-thread check
only looked at EmojiReact, so a thread whose only local interaction was
such a reaction was evicted.
Eviction took the object ids of every activity in a thread. A Like or
Announce whose context differs from its object's then deleted a post in
another, possibly pinned thread. Found on a copy of a real instance:
593 posts from threads with local activity in the first 2M objects.
A mention or DM was only pinned by its notification, so clearing
notifications let retention evict a user's direct messages. Check the
activity recipients instead, which does not go away.
Also splits generic dependencies into elixir/erlang and the rest.
Generic depenencies then import the elixir/erlang snippets to preserve
previous layout.
Fixes:
mint 1.9.3 - EEF-CVE-2026-82729 (MEDIUM)
aka: CVE-2026-82729, GHSA-7p8w-j234-7qc8
Quadratic chunk-size parsing in Mint.HTTP1.Parse allows CPU-exhaustion DoS
https://osv.dev/vulnerability/EEF-CVE-2026-82729
mint 1.9.3 - EEF-CVE-2026-82728 (HIGH)
aka: CVE-2026-82728, GHSA-g83f-2j6r-q6m4
Unbounded HTTP/1 status-line and chunk-extension buffering in Mint causes memory-exhaustion DoS
https://osv.dev/vulnerability/EEF-CVE-2026-82728
Wrap the followed ap_ids subselect in keep_following_or_not_domain_blocked
in ARRAY(...) so it becomes an InitPlan. As a plain subselect the planner
charged its startup per rescan of the actor lookup, which could make
Notification.for_user pick a plan that scans every active user per row.
Grouping the whole activities table by thread every run is unusable on
a large instance: on a 312 GB database it plans as a seq scan plus a
50M-row on-disk sort. Instead, walk activities in id order (flake ids
are time-ordered) from a persisted cursor up to the id that corresponds
to the deadline, and verify only the threads those activities belong to
through the (type, context) index. Measured on that instance: 147 ms
for a 50k-activity range scan, 349 ms warm / 14 s cold to verify ~700
threads.
The cursor is persisted per chunk so a killed run resumes. The
watermark walk keeps a cursor of its own so it cannot leave the
age-based walk stranded behind the deadline. Adds the retention_cursors
table.
prune_objects --keep-threads now shares the thread selection with
Pleroma.Retention, which additionally keeps threads that mention a
local user or that are referenced by a report. The hashtag cleanup
is shared as well.
Pleroma.Retention treats remote content as a cache: a thread is evicted
once nobody local has interacted with it and it has been quiet for
longer than remote_post_retention_days, or when the objects table is
over an optional row watermark. Local posts are never deleted.
A single grouping scan collects activity and object ids per thread so
the deletes only touch primary key and ap_id indexes.