feat: a teaser's card references the drop it announced and the piece's variants (4402, 4401)

The operator's problem: a Patreon teaser is a pointer, and its card showed the
censored crop plus a text link while the content it pointed at sat on another
card. The fix is a REFERENCE, not an absorption: "the nested items on the
unified post are a duplicate or reference of existing content". Nothing is
written. Discord posts keep their own rows, dates and places in the feed.

- post_unification: for each teaser with a linked association, the drop's
  images and text, plus its variant family: Discord images sharing the
  seed's gated LEADING working name, or a phash near-duplicate, within a
  window of the teaser. One hop only, oldest first.
- Measured on artist 8 before writing it: of 121 message pairs 2-60 days
  apart that share a gated token, 106 share the leading name and all read
  as real families. Of the 15 sharing only a trailing word, 14 are sibling
  pieces and one is a plain collision (`bottom`, 56 days). The family cap
  is 8, not the pairing cap of 6, because `tentacooler` and `0-k1` (6 posts
  each) are real families.
- The feed drops a linked drop's own card only within discord_link_fold_hours
  of its teaser (default 24): "only hidden from the post view they're posted
  the same day". Older referenced posts stay where they landed.
- post_association.linked_by records whether FC or a person made the link,
  so the card can say so. Undo is the existing dismiss.
- `image0` (gallery-dl's fallback name) becomes a stopword.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LVjrnpQjRgHdvq95rASoiR
This commit is contained in:
2026-09-24 11:25:52 -04:00
co-authored by Claude Opus 5.5
parent f7b3e15014
commit 30a263a47a
11 changed files with 1087 additions and 11 deletions
+45
View File
@@ -20,6 +20,7 @@ from backend.app.services.post_naming import (
IDENTITY_FLOOR,
MAX_MARKER_POSTS,
MAX_TOKEN_POSTS,
leading_name,
marker_frequencies,
marker_overlap,
shared_identity,
@@ -305,3 +306,47 @@ def test_marker_overlap_cannot_be_called_without_the_frequencies():
write by accident. A default would have kept it one keyword away."""
with pytest.raises(TypeError):
marker_overlap("\U0001F348", "\U0001F348")
# --- the leading name: what a variant family is keyed on (#4401) ------------
@pytest.mark.parametrize(
"path, expected",
[
("20240301_1213141516171819_01_Year_20K_wip3.png", "year"),
("20240414_1213141516171820_01_not_sombra_21-cumpeen.png", "not"),
("20240101_1213141516171821_02_Tentacooler_c_ins.png", "tentacooler"),
("01_((0-k.jpg", "0-k"),
# The legacy era's `0071` has no letter, so the name is the first
# token that IS one — not "whatever came first".
("85317841_media_212565911_0071 NoHeart__c3118a69f3__c3118a69f3.jpg", "noheart"),
],
)
def test_the_leading_name_is_the_piece_not_its_decoration(path, expected):
assert leading_name(path) == expected
def test_a_trailing_content_word_is_never_the_leading_name():
"""Measured: `Undyne_insert_bottom_only-C` and `Lichgalclc_Lingerie_Bottom_21`
share `bottom`, 56 days apart, and are unrelated. `bottom` spans only three
posts, so no frequency cap can refuse it — position is what does."""
assert leading_name("Undyne_insert_bottom_only-C.png") == "undyne"
assert leading_name("Lichgalclc_Lingerie_Bottom_21.png") == "lichgalclc"
@pytest.mark.parametrize(
"path",
["01_Screenshot 2026-08-13 000004.png", "20240101_1213141516171822_01_image0.png"],
)
def test_a_name_with_no_identity_has_no_leading_name(path):
"""`image0` is gallery-dl's fallback for an attachment with no name —
measured on four unrelated images across 1,974 days."""
assert leading_name(path) is None
def test_the_leading_name_is_always_one_of_the_names():
"""One tokenizer serves both readings, so they cannot disagree about what
counts as a name."""
path = "20240301_1213141516171819_01_Year_20K_wip3.png"
assert leading_name(path) in working_name_tokens(path)