Never match a date separator as a summary anchor

Date separators are local MessageObjects that live in the same
ChatActivity.messages list as real messages, and ChatActivity builds them
with messageOwner.id left at 0 (their stable ids come from a separate
dateObjectsStableIds space, so they never collide with injected cards).

find_index_for_anchor scanned for an exact id match without requiring a
positive id, so looking up anchor 0 returned the index of the first
separator and would have placed a card against a divider rather than a
message. loaded_message_ids had the matching flaw: it recorded the
separators' 0, which made a summary with anchor id 0 look restorable.

Reject non-positive anchors outright and keep separators out of the loaded
id set. Every real chat interleaves separators, so the harness now models
them: they must not be picked as the insertion point, must not satisfy an
anchor-loaded check, and summaries anchored on real messages must still
restore correctly with separators in between.
This commit is contained in:
lyuksovannyy committed 2026-09-19 16:54:25 +02:00
1 parent 0619c5fe68
commit b05d1a274c
2 files changed
+57 -2

No files matched your search

+13 -2
View File
@@ -195,6 +195,12 @@ def find_index_for_anchor(messages_list: Any, anchor_msg_id: int, require_anchor
again once the anchor is paged in.
"""
anchor_msg_id = int(anchor_msg_id)
# Anchors are real, positive message ids. A non-positive anchor must never
# match: date separators are local MessageObjects whose messageOwner.id is
# 0, so scanning for 0 would "find" the first separator and place the card
# against a divider instead of a message.
if anchor_msg_id <= 0:
return -1
try:
size = messages_list.size()
for i in range(size):
@@ -558,8 +564,13 @@ def loaded_message_ids(messages_list: Any) -> set:
try:
for i in range(messages_list.size()):
owner = getattr(messages_list.get(i), "messageOwner", None)
if owner is not None:
ids.add(int(getattr(owner, "id", 0) or 0))
if owner is None:
continue
msg_id = int(getattr(owner, "id", 0) or 0)
# Skip date separators (id 0). Keeping them would make a summary
# whose anchor id is 0 look restorable.
if msg_id:
ids.add(msg_id)
except Exception as exc:
diagnostics.record_error("injector.loaded_message_ids", exc)
return ids