generated from exteraGramPlugins/pluginBase
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:
1 parent
0619c5fe68
commit
b05d1a274c
2 files changed
+57
-2
No files matched your search
@@ -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.
|
again once the anchor is paged in.
|
||||||
"""
|
"""
|
||||||
anchor_msg_id = int(anchor_msg_id)
|
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:
|
try:
|
||||||
size = messages_list.size()
|
size = messages_list.size()
|
||||||
for i in range(size):
|
for i in range(size):
|
||||||
@@ -558,8 +564,13 @@ def loaded_message_ids(messages_list: Any) -> set:
|
|||||||
try:
|
try:
|
||||||
for i in range(messages_list.size()):
|
for i in range(messages_list.size()):
|
||||||
owner = getattr(messages_list.get(i), "messageOwner", None)
|
owner = getattr(messages_list.get(i), "messageOwner", None)
|
||||||
if owner is not None:
|
if owner is None:
|
||||||
ids.add(int(getattr(owner, "id", 0) or 0))
|
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:
|
except Exception as exc:
|
||||||
diagnostics.record_error("injector.loaded_message_ids", exc)
|
diagnostics.record_error("injector.loaded_message_ids", exc)
|
||||||
return ids
|
return ids
|
||||||
|
|||||||
@@ -1927,6 +1927,50 @@ def main(argv=None) -> int:
|
|||||||
f"index={injector.find_index_for_anchor(absent.messages, 123, require_anchor=False)}",
|
f"index={injector.find_index_for_anchor(absent.messages, 123, require_anchor=False)}",
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# Every real chat interleaves date separators, which are local
|
||||||
|
# MessageObjects carrying messageOwner.id == 0 (ChatActivity builds them
|
||||||
|
# with `iput v12, ...Message->id` where v12 is 0, and gives them ids from
|
||||||
|
# a separate dateObjectsStableIds space). They must never be treated as
|
||||||
|
# the insertion point or counted as a loaded anchor.
|
||||||
|
dated = _FakeChatActivity([700, 690])
|
||||||
|
separator_owner = _TLObj("TL_messageService")
|
||||||
|
separator_owner.id = 0
|
||||||
|
dated.messages.add(1, _FakeMessageObject(0, separator_owner))
|
||||||
|
dated_index = injector.find_index_for_anchor(dated.messages, 690)
|
||||||
|
dated_ids = [m.messageOwner.id for m in dated.messages]
|
||||||
|
check(
|
||||||
|
"a date separator is not mistaken for the anchor",
|
||||||
|
dated_ids[dated_index] == 690,
|
||||||
|
f"index={dated_index} ids={dated_ids}",
|
||||||
|
)
|
||||||
|
# A separator's id 0 must not make "anchor 0" look loaded, and must not
|
||||||
|
# be offered as a position; anchor ids are always positive.
|
||||||
|
check(
|
||||||
|
"a date separator does not satisfy an anchor-loaded check",
|
||||||
|
injector.find_index_for_anchor(dated.messages, 0) == -1,
|
||||||
|
f"index={injector.find_index_for_anchor(dated.messages, 0)}",
|
||||||
|
)
|
||||||
|
# A summary anchored on a real message must still restore correctly when
|
||||||
|
# separators sit between the loaded messages.
|
||||||
|
sep_restore = _FakeChatActivity([800, 790])
|
||||||
|
sep_owner = _TLObj("TL_messageService")
|
||||||
|
sep_owner.id = 0
|
||||||
|
sep_restore.messages.add(1, _FakeMessageObject(0, sep_owner))
|
||||||
|
sep_n = injector.restore_saved_summaries(
|
||||||
|
sep_restore,
|
||||||
|
0,
|
||||||
|
-4242,
|
||||||
|
0,
|
||||||
|
[summary_db_mod.StoredSummary(41, -4242, 0, 790, "text", "", 5, 0)],
|
||||||
|
)
|
||||||
|
sep_ids = [m.messageOwner.id for m in sep_restore.messages]
|
||||||
|
sep_card = injector.virtual_id_for(41, 790)
|
||||||
|
check(
|
||||||
|
"summaries restore correctly around date separators",
|
||||||
|
sep_n == 1 and sep_ids.index(sep_card) == sep_ids.index(790) - 1,
|
||||||
|
f"dispatched={sep_n} ids={sep_ids}",
|
||||||
|
)
|
||||||
|
|
||||||
check(
|
check(
|
||||||
"sys.modules gained no entry for bundled plugin module names",
|
"sys.modules gained no entry for bundled plugin module names",
|
||||||
not ({"main", "config", "services", "providers", "hooks", "ui.summarize_dialog"} & new_modules),
|
not ({"main", "config", "services", "providers", "hooks", "ui.summarize_dialog"} & new_modules),
|
||||||
|
|||||||
Reference in new issue
Block a user