..............................F...F..................................... [ 3%] ........................................................................ [ 7%] .........FF..............................................F.............. [ 10%] .................F...................................................... [ 14%] .........................................FFFFFFFF...............F....... [ 17%] ........................................................................ [ 21%] ........................................................................ [ 24%] ........................................................................ [ 28%] ........................................................................ [ 31%] ........................................................................ [ 35%] ......................................................... [ 38%] ..........F............................................................. [ 41%] ........................................F............................... [ 45%] ...................................FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF [ 49%] FFF..FF.........................FFF..................................... [ 52%] ........................................................................ [ 56%] ...................sss..s............................................... [ 59%] ........................................................................ [ 63%] ........................................................................ [ 66%] ........................................................F............... [ 70%] ........................FF........................................... [ 73%] ........................................................................ [ 77%] .................ss..................................................... [ 80%] .........FFF............................................................ [ 84%] .....................................sssssssssssssssssssssssss.......... [ 87%] ...........................................FFFF.FF....FF...F....F....... [ 91%] ........................................................................ [ 95%] ...................................sss.................................. [ 98%] ......................s..F.. [100%] =================================== FAILURES =================================== _____________ test_edges_cite_journal_records_across_chosen_chats ______________ store = (, {'pay': {'seq': 1, 'observed_at': '2026-11-14T06:13:36.542+00:00', ...ward': {'seq': 4, 'observed_at': '2026-11-14T06:13:36.560+00:00', 'source_at': None, 'kind': 'message.new', ...}, ...}) def test_edges_cite_journal_records_across_chosen_chats(store): value, records = store model = graphs.collect(extensions.JournalReader(lambda: value), {CHAT, OTHER}) reply = edge(model, "account:22", "account:11", "reply") assert reply["weight"] == 1 and reply["refs"] == [{"chat": CHAT, "message": 2, "seq": records["reply"]["seq"], "hash": records["reply"]["hash"]}] assert edge(model, "account:11", "account:22", "reply")["refs"][0]["seq"] == records["back"]["seq"] assert edge(model, "account:33", "source:-1000000000555", "forward")["refs"][0]["message"] == 4 assert edge(model, "account:22", "mention:@helper_bot", "mention")["weight"] == 1 wallet = "indicator:wallet:" + WALLET assert {e["source"] for e in model["edges"] if e["target"] == wallet} == {"account:11", "account:33"} assert edge(model, "account:33", wallet, "posted")["refs"][0]["chat"] == OTHER assert model["totals"]["indicators_shared_by_several"] == 1 and model["format"] == graphs.FORMAT nodes = {n["id"]: n for n in model["nodes"]} assert nodes["account:11"]["label"] == "Alice &" and nodes["account:11"]["messages"] == 2 assert nodes["account:11"]["community"] == nodes["account:22"]["community"] assert all(len(e["refs"]) <= graphs.MAX_REFS for e in model["edges"]) and not model["truncated"] > assert any("does not mean there was no contact" in line for line in model["limits"]) E assert False E + where False = any(. at 0x7dd266e74380>) tools/test_analyzer_graphs.py:71: AssertionError _______ test_rotated_account_ranks_first_with_explanation_and_citations ________ reader = def test_rotated_account_ranks_first_with_explanation_and_citations(reader): result = linking.candidates(reader, {CHAT}, offset_minutes=180) assert result["format"] == linking.FORMAT and result["accounts"] == 5 and result["compared"] == 10 assert result["basis"] == "absolute" top = result["pairs"][0] assert top["key"] == "101|202" and top["tier"] == "strong" assert all(top["score"] > pair["score"] for pair in result["pairs"][1:]) assert {"lexical", "hours", "handoff", "shared"} <= set(top["standout"]) assert top["handoff"]["gone"] == 101 and top["handoff"]["arrived"] == 202 assert any(line.startswith("Same vocabulary") for line in top["explanation"]) assert any(line.startswith("One stops, other starts: Payout Desk (ID 101)") for line in top["explanation"]) [shared] = top["shared_indicators"] assert shared["kind"] == "wallet" and shared["value"] == WALLET assert all(len(ref["hash"]) == 64 and ref["chat"] == CHAT for ref in shared["refs"] + top["a"]["refs"]) assert top["a"]["first_seen"].endswith("+03:00") > assert any("not identification" in line for line in result["limits"]) E assert False E + where False = any(. at 0x7dd2667a2dc0>) tools/test_analyzer_linking.py:81: AssertionError ______ test_package_contains_readable_report_files_and_explanations[tsr] _______ tmp_path = PosixPath('/tmp/pytest-of-root/pytest-5/test_package_contains_readable0') receipt_kind = 'tsr' @pytest.mark.parametrize("receipt_kind", ["tsr", "ots"]) def test_package_contains_readable_report_files_and_explanations(tmp_path, receipt_kind): vault, store = Vault(tmp_path / "workspace"), Store(tmp_path / "workspace") store.bind(vault) media = tmp_path / "workspace" / "media" media.mkdir(exist_ok=True) for data in (PHOTO, SECRET): (media / sha(data)).write_bytes(data) try: session = documentation.create(store, Start(title="Fictional case"), "admin") store.append("interaction.requested", {"request": {"action": "send", "chat_id": BOT, "text": "hi"}}, BOT) store.append("message.new", {**incoming("hi"), "outgoing": True, "source": "panel_action"}, BOT, 1) store.append("message.new", incoming("Pay to bc1qw508d6qejxtdg4y5r3zarvary0c5xw7kv8f3t4"), BOT, 2) store.append("media.saved", {"media_sha256": sha(PHOTO), "mime_type": "image/jpeg"}, BOT, 2) hidden = store.append("message.new", incoming("explicit"), BOT, 3) store.append("media.saved", {"media_sha256": sha(SECRET), "mime_type": "image/jpeg"}, BOT, 3) store.append("capture.opened", {"requested_url": "https://pay.example.invalid/", "http_status": 200, "artifacts": [{"sha256": sha(SCREEN), "size": len(SCREEN), "role": "viewport", "media_type": "image/png"}], "errors": []}) documentation.add_mark(store, session["id"], Mark(text="Explicit", labels=["adult"], target_seq=hidden["seq"])) with pytest.raises(ValueError, match="Fix the document"): case_package.build(documentation.load(store, session["id"]), documentation.action_protocol.plain_say, {}, media) fixed = documentation.fix(store, vault, session["id"])["fixed"] checkpoints = tmp_path / "workspace" / "checkpoints" (checkpoints / "anchors").mkdir(parents=True, exist_ok=True) name = "checkpoint-" + str(fixed["event_seq"] + 1).zfill(12) receipt_name = name + ".fictional-tsa." + receipt_kind (checkpoints / (name + ".json")).write_text('{"statement": {}}') (checkpoints / "anchors" / receipt_name).write_bytes(b"synthetic-reply") loaded = documentation.load(store, session["id"]) path = case_package.build(loaded, documentation.action_protocol.plain_say, {sha(SCREEN): SCREEN}, media, tmp_path, checkpoints) root = "tgwitness-case-" + session["id"][:8] + "/" with zipfile.ZipFile(path) as archive: names = set(archive.namelist()) slides = archive.read(root + "data/presentation.html").decode() assert slides.count('
assert "Timestamp receipts (not verified)" in certificate and "have not been verified" in certificate E assert ('Timestamp receipts (not verified)' in '

Date:

Place:

') tools/test_case_package.py:82: AssertionError ______ test_package_contains_readable_report_files_and_explanations[ots] _______ tmp_path = PosixPath('/tmp/pytest-of-root/pytest-5/test_package_contains_readable1') receipt_kind = 'ots' @pytest.mark.parametrize("receipt_kind", ["tsr", "ots"]) def test_package_contains_readable_report_files_and_explanations(tmp_path, receipt_kind): vault, store = Vault(tmp_path / "workspace"), Store(tmp_path / "workspace") store.bind(vault) media = tmp_path / "workspace" / "media" media.mkdir(exist_ok=True) for data in (PHOTO, SECRET): (media / sha(data)).write_bytes(data) try: session = documentation.create(store, Start(title="Fictional case"), "admin") store.append("interaction.requested", {"request": {"action": "send", "chat_id": BOT, "text": "hi"}}, BOT) store.append("message.new", {**incoming("hi"), "outgoing": True, "source": "panel_action"}, BOT, 1) store.append("message.new", incoming("Pay to bc1qw508d6qejxtdg4y5r3zarvary0c5xw7kv8f3t4"), BOT, 2) store.append("media.saved", {"media_sha256": sha(PHOTO), "mime_type": "image/jpeg"}, BOT, 2) hidden = store.append("message.new", incoming("explicit"), BOT, 3) store.append("media.saved", {"media_sha256": sha(SECRET), "mime_type": "image/jpeg"}, BOT, 3) store.append("capture.opened", {"requested_url": "https://pay.example.invalid/", "http_status": 200, "artifacts": [{"sha256": sha(SCREEN), "size": len(SCREEN), "role": "viewport", "media_type": "image/png"}], "errors": []}) documentation.add_mark(store, session["id"], Mark(text="Explicit", labels=["adult"], target_seq=hidden["seq"])) with pytest.raises(ValueError, match="Fix the document"): case_package.build(documentation.load(store, session["id"]), documentation.action_protocol.plain_say, {}, media) fixed = documentation.fix(store, vault, session["id"])["fixed"] checkpoints = tmp_path / "workspace" / "checkpoints" (checkpoints / "anchors").mkdir(parents=True, exist_ok=True) name = "checkpoint-" + str(fixed["event_seq"] + 1).zfill(12) receipt_name = name + ".fictional-tsa." + receipt_kind (checkpoints / (name + ".json")).write_text('{"statement": {}}') (checkpoints / "anchors" / receipt_name).write_bytes(b"synthetic-reply") loaded = documentation.load(store, session["id"]) path = case_package.build(loaded, documentation.action_protocol.plain_say, {sha(SCREEN): SCREEN}, media, tmp_path, checkpoints) root = "tgwitness-case-" + session["id"][:8] + "/" with zipfile.ZipFile(path) as archive: names = set(archive.namelist()) slides = archive.read(root + "data/presentation.html").decode() assert slides.count('
assert "Timestamp receipts (not verified)" in certificate and "have not been verified" in certificate E assert ('Timestamp receipts (not verified)' in '

Date:

Place:

') tools/test_case_package.py:82: AssertionError __________ test_sparse_message_numbers_are_counted_without_expansion ___________ tmp_path = PosixPath('/tmp/pytest-of-root/pytest-5/test_sparse_message_numbers_ar0') def test_sparse_message_numbers_are_counted_without_expansion(tmp_path): scratch = tmp_path / "sparse.jsonl" scratch.write_text('{"id":1}\n{"id":2000000000}\n', encoding="utf-8") missing = absent_numbers(scratch) > assert len(missing) == 1999999998 E assert 2 == 1999999998 E + where 2 = len((, 1)) tools/test_chat_export_integrity.py:100: AssertionError _____________________________ test_local_commands ______________________________ workspace = PosixPath('/tmp/pytest-of-root/pytest-5/test_local_commands0') capsys = <_pytest.capture.CaptureFixture object at 0x7dd25c32af60> def test_local_commands(workspace, capsys): base = ("--data-dir", str(workspace)) found = document(capsys, "search", "перевод", *base) assert found["ranked"] and {item["source"]["message_id"] for item in found["items"]} == {1, 2} assert all(item["source"]["chat_id"] == CHAT and item["untrusted_content"] for item in found["items"]) exact = document(capsys, "search", "Оплата", "--exact", *base) assert not exact.get("ranked") and {item["kind"] for item in exact["items"]} == {"message.new", "message.edited"} near = document(capsys, "context", str(CHAT), "2", *base) assert {item["source"]["message_id"] for item in near["items"]} == {1, 2, 3, 4} chats = document(capsys, "messages", *base) assert {item["chat_id"] for item in chats["items"]} == {CHAT, OTHER} names = document(capsys, "messages", "--workspaces", *base) > assert names["items"] == [{"workspace": "default", "name": "Main account"}] E AssertionError: assert [{'workspace'...n workspace'}] == [{'workspace'...ain account'}] E E At index 0 diff: {'workspace': 'default', 'name': 'Main workspace'} != {'workspace': 'default', 'name': 'Main account'} E Use -v to get more diff tools/test_cli.py:147: AssertionError ____ test_deletion_of_subset_keeps_actor_and_whole_history_unknown[2-55123] ____ tmp_path = PosixPath('/tmp/pytest-of-root/pytest-5/test_deletion_of_subset_keeps_0') chat_id = 55123, count = 2 @pytest.mark.parametrize("chat_id", [55123, -1000000000555]) @pytest.mark.parametrize("count", [2, 9, 10, 15]) def test_deletion_of_subset_keeps_actor_and_whole_history_unknown(tmp_path, chat_id, count): async def scenario(): vault, store = Vault(tmp_path), Store(tmp_path) store.bind(vault) store.set_target(chat_id, "Synthetic evidence review", "private" if chat_id > 0 else "supergroup", True) collector = Collector(store, vault) collector.running = True ids = list(range(1, count + 1)) try: for mid in [*ids, 100]: store.append("message.new", {"text": f"Synthetic message {mid}", "outgoing": mid == 1, "sent_at": "2026-11-05T12:00:00+00:00", "edited_at": None}, chat_id, mid) raw = (types.UpdateDeleteMessages(messages=ids, pts=1, pts_count=count) if chat_id > 0 else types.UpdateDeleteChannelMessages(channel_id=555, messages=ids, pts=1, pts_count=count)) await collector.on_delete(SimpleNamespace(chat_id=None if chat_id > 0 else chat_id, deleted_ids=ids, original_update=raw)) assert store.message_state(chat_id, 100)["deleted"] is False events = list(store.all_events()) summaries = [e for e in events if e["kind"] in ("deletion.batch", "history.cleared")] assert len(summaries) == 1 summary = summaries[0] assert summary["kind"] == "deletion.batch", "A subset deletion is not a whole-history clear" assert summary["payload"]["outgoing_saved"] == 1 assert summary["payload"]["raw"] == raw.to_dict() assert "other side cleared" not in summary["payload"]["meaning"] assert "does not identify who deleted them" in summary["payload"]["meaning"] deleted = [e for e in events if e["kind"] == "message.deleted"] assert len(deleted) == count assert all(e["payload"]["deleted_by"] is None for e in deleted) assert all(e["payload"]["deletion_time"] is None for e in deleted) assert all(e["payload"]["batch"]["hash"] == summary["hash"] for e in deleted) store.verify(vault.public_key) finally: store.close() > asyncio.run(scenario()) tools/test_deletion_semantics.py:52: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3.12/asyncio/runners.py:194: in run return runner.run(main) ^^^^^^^^^^^^^^^^ /usr/lib/python3.12/asyncio/runners.py:118: in run return self._loop.run_until_complete(task) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.12/asyncio/base_events.py:687: in run_until_complete return future.result() ^^^^^^^^^^^^^^^ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ async def scenario(): vault, store = Vault(tmp_path), Store(tmp_path) store.bind(vault) store.set_target(chat_id, "Synthetic evidence review", "private" if chat_id > 0 else "supergroup", True) collector = Collector(store, vault) collector.running = True ids = list(range(1, count + 1)) try: for mid in [*ids, 100]: store.append("message.new", {"text": f"Synthetic message {mid}", "outgoing": mid == 1, "sent_at": "2026-11-05T12:00:00+00:00", "edited_at": None}, chat_id, mid) raw = (types.UpdateDeleteMessages(messages=ids, pts=1, pts_count=count) if chat_id > 0 else types.UpdateDeleteChannelMessages(channel_id=555, messages=ids, pts=1, pts_count=count)) await collector.on_delete(SimpleNamespace(chat_id=None if chat_id > 0 else chat_id, deleted_ids=ids, original_update=raw)) assert store.message_state(chat_id, 100)["deleted"] is False events = list(store.all_events()) summaries = [e for e in events if e["kind"] in ("deletion.batch", "history.cleared")] assert len(summaries) == 1 summary = summaries[0] assert summary["kind"] == "deletion.batch", "A subset deletion is not a whole-history clear" assert summary["payload"]["outgoing_saved"] == 1 assert summary["payload"]["raw"] == raw.to_dict() assert "other side cleared" not in summary["payload"]["meaning"] > assert "does not identify who deleted them" in summary["payload"]["meaning"] E AssertionError: assert 'does not identify who deleted them' in 'Telegram reported several message IDs as deleted in one update.' tools/test_deletion_semantics.py:43: AssertionError _ test_deletion_of_subset_keeps_actor_and_whole_history_unknown[2--1000000000555] _ tmp_path = PosixPath('/tmp/pytest-of-root/pytest-5/test_deletion_of_subset_keeps_1') chat_id = -1000000000555, count = 2 @pytest.mark.parametrize("chat_id", [55123, -1000000000555]) @pytest.mark.parametrize("count", [2, 9, 10, 15]) def test_deletion_of_subset_keeps_actor_and_whole_history_unknown(tmp_path, chat_id, count): async def scenario(): vault, store = Vault(tmp_path), Store(tmp_path) store.bind(vault) store.set_target(chat_id, "Synthetic evidence review", "private" if chat_id > 0 else "supergroup", True) collector = Collector(store, vault) collector.running = True ids = list(range(1, count + 1)) try: for mid in [*ids, 100]: store.append("message.new", {"text": f"Synthetic message {mid}", "outgoing": mid == 1, "sent_at": "2026-11-05T12:00:00+00:00", "edited_at": None}, chat_id, mid) raw = (types.UpdateDeleteMessages(messages=ids, pts=1, pts_count=count) if chat_id > 0 else types.UpdateDeleteChannelMessages(channel_id=555, messages=ids, pts=1, pts_count=count)) await collector.on_delete(SimpleNamespace(chat_id=None if chat_id > 0 else chat_id, deleted_ids=ids, original_update=raw)) assert store.message_state(chat_id, 100)["deleted"] is False events = list(store.all_events()) summaries = [e for e in events if e["kind"] in ("deletion.batch", "history.cleared")] assert len(summaries) == 1 summary = summaries[0] assert summary["kind"] == "deletion.batch", "A subset deletion is not a whole-history clear" assert summary["payload"]["outgoing_saved"] == 1 assert summary["payload"]["raw"] == raw.to_dict() assert "other side cleared" not in summary["payload"]["meaning"] assert "does not identify who deleted them" in summary["payload"]["meaning"] deleted = [e for e in events if e["kind"] == "message.deleted"] assert len(deleted) == count assert all(e["payload"]["deleted_by"] is None for e in deleted) assert all(e["payload"]["deletion_time"] is None for e in deleted) assert all(e["payload"]["batch"]["hash"] == summary["hash"] for e in deleted) store.verify(vault.public_key) finally: store.close() > asyncio.run(scenario()) tools/test_deletion_semantics.py:52: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3.12/asyncio/runners.py:194: in run return runner.run(main) ^^^^^^^^^^^^^^^^ /usr/lib/python3.12/asyncio/runners.py:118: in run return self._loop.run_until_complete(task) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.12/asyncio/base_events.py:687: in run_until_complete return future.result() ^^^^^^^^^^^^^^^ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ async def scenario(): vault, store = Vault(tmp_path), Store(tmp_path) store.bind(vault) store.set_target(chat_id, "Synthetic evidence review", "private" if chat_id > 0 else "supergroup", True) collector = Collector(store, vault) collector.running = True ids = list(range(1, count + 1)) try: for mid in [*ids, 100]: store.append("message.new", {"text": f"Synthetic message {mid}", "outgoing": mid == 1, "sent_at": "2026-11-05T12:00:00+00:00", "edited_at": None}, chat_id, mid) raw = (types.UpdateDeleteMessages(messages=ids, pts=1, pts_count=count) if chat_id > 0 else types.UpdateDeleteChannelMessages(channel_id=555, messages=ids, pts=1, pts_count=count)) await collector.on_delete(SimpleNamespace(chat_id=None if chat_id > 0 else chat_id, deleted_ids=ids, original_update=raw)) assert store.message_state(chat_id, 100)["deleted"] is False events = list(store.all_events()) summaries = [e for e in events if e["kind"] in ("deletion.batch", "history.cleared")] assert len(summaries) == 1 summary = summaries[0] assert summary["kind"] == "deletion.batch", "A subset deletion is not a whole-history clear" assert summary["payload"]["outgoing_saved"] == 1 assert summary["payload"]["raw"] == raw.to_dict() assert "other side cleared" not in summary["payload"]["meaning"] > assert "does not identify who deleted them" in summary["payload"]["meaning"] E AssertionError: assert 'does not identify who deleted them' in 'Telegram reported several message IDs as deleted in one update.' tools/test_deletion_semantics.py:43: AssertionError ____ test_deletion_of_subset_keeps_actor_and_whole_history_unknown[9-55123] ____ tmp_path = PosixPath('/tmp/pytest-of-root/pytest-5/test_deletion_of_subset_keeps_2') chat_id = 55123, count = 9 @pytest.mark.parametrize("chat_id", [55123, -1000000000555]) @pytest.mark.parametrize("count", [2, 9, 10, 15]) def test_deletion_of_subset_keeps_actor_and_whole_history_unknown(tmp_path, chat_id, count): async def scenario(): vault, store = Vault(tmp_path), Store(tmp_path) store.bind(vault) store.set_target(chat_id, "Synthetic evidence review", "private" if chat_id > 0 else "supergroup", True) collector = Collector(store, vault) collector.running = True ids = list(range(1, count + 1)) try: for mid in [*ids, 100]: store.append("message.new", {"text": f"Synthetic message {mid}", "outgoing": mid == 1, "sent_at": "2026-11-05T12:00:00+00:00", "edited_at": None}, chat_id, mid) raw = (types.UpdateDeleteMessages(messages=ids, pts=1, pts_count=count) if chat_id > 0 else types.UpdateDeleteChannelMessages(channel_id=555, messages=ids, pts=1, pts_count=count)) await collector.on_delete(SimpleNamespace(chat_id=None if chat_id > 0 else chat_id, deleted_ids=ids, original_update=raw)) assert store.message_state(chat_id, 100)["deleted"] is False events = list(store.all_events()) summaries = [e for e in events if e["kind"] in ("deletion.batch", "history.cleared")] assert len(summaries) == 1 summary = summaries[0] assert summary["kind"] == "deletion.batch", "A subset deletion is not a whole-history clear" assert summary["payload"]["outgoing_saved"] == 1 assert summary["payload"]["raw"] == raw.to_dict() assert "other side cleared" not in summary["payload"]["meaning"] assert "does not identify who deleted them" in summary["payload"]["meaning"] deleted = [e for e in events if e["kind"] == "message.deleted"] assert len(deleted) == count assert all(e["payload"]["deleted_by"] is None for e in deleted) assert all(e["payload"]["deletion_time"] is None for e in deleted) assert all(e["payload"]["batch"]["hash"] == summary["hash"] for e in deleted) store.verify(vault.public_key) finally: store.close() > asyncio.run(scenario()) tools/test_deletion_semantics.py:52: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3.12/asyncio/runners.py:194: in run return runner.run(main) ^^^^^^^^^^^^^^^^ /usr/lib/python3.12/asyncio/runners.py:118: in run return self._loop.run_until_complete(task) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.12/asyncio/base_events.py:687: in run_until_complete return future.result() ^^^^^^^^^^^^^^^ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ async def scenario(): vault, store = Vault(tmp_path), Store(tmp_path) store.bind(vault) store.set_target(chat_id, "Synthetic evidence review", "private" if chat_id > 0 else "supergroup", True) collector = Collector(store, vault) collector.running = True ids = list(range(1, count + 1)) try: for mid in [*ids, 100]: store.append("message.new", {"text": f"Synthetic message {mid}", "outgoing": mid == 1, "sent_at": "2026-11-05T12:00:00+00:00", "edited_at": None}, chat_id, mid) raw = (types.UpdateDeleteMessages(messages=ids, pts=1, pts_count=count) if chat_id > 0 else types.UpdateDeleteChannelMessages(channel_id=555, messages=ids, pts=1, pts_count=count)) await collector.on_delete(SimpleNamespace(chat_id=None if chat_id > 0 else chat_id, deleted_ids=ids, original_update=raw)) assert store.message_state(chat_id, 100)["deleted"] is False events = list(store.all_events()) summaries = [e for e in events if e["kind"] in ("deletion.batch", "history.cleared")] assert len(summaries) == 1 summary = summaries[0] assert summary["kind"] == "deletion.batch", "A subset deletion is not a whole-history clear" assert summary["payload"]["outgoing_saved"] == 1 assert summary["payload"]["raw"] == raw.to_dict() assert "other side cleared" not in summary["payload"]["meaning"] > assert "does not identify who deleted them" in summary["payload"]["meaning"] E AssertionError: assert 'does not identify who deleted them' in 'Telegram reported several message IDs as deleted in one update.' tools/test_deletion_semantics.py:43: AssertionError _ test_deletion_of_subset_keeps_actor_and_whole_history_unknown[9--1000000000555] _ tmp_path = PosixPath('/tmp/pytest-of-root/pytest-5/test_deletion_of_subset_keeps_3') chat_id = -1000000000555, count = 9 @pytest.mark.parametrize("chat_id", [55123, -1000000000555]) @pytest.mark.parametrize("count", [2, 9, 10, 15]) def test_deletion_of_subset_keeps_actor_and_whole_history_unknown(tmp_path, chat_id, count): async def scenario(): vault, store = Vault(tmp_path), Store(tmp_path) store.bind(vault) store.set_target(chat_id, "Synthetic evidence review", "private" if chat_id > 0 else "supergroup", True) collector = Collector(store, vault) collector.running = True ids = list(range(1, count + 1)) try: for mid in [*ids, 100]: store.append("message.new", {"text": f"Synthetic message {mid}", "outgoing": mid == 1, "sent_at": "2026-11-05T12:00:00+00:00", "edited_at": None}, chat_id, mid) raw = (types.UpdateDeleteMessages(messages=ids, pts=1, pts_count=count) if chat_id > 0 else types.UpdateDeleteChannelMessages(channel_id=555, messages=ids, pts=1, pts_count=count)) await collector.on_delete(SimpleNamespace(chat_id=None if chat_id > 0 else chat_id, deleted_ids=ids, original_update=raw)) assert store.message_state(chat_id, 100)["deleted"] is False events = list(store.all_events()) summaries = [e for e in events if e["kind"] in ("deletion.batch", "history.cleared")] assert len(summaries) == 1 summary = summaries[0] assert summary["kind"] == "deletion.batch", "A subset deletion is not a whole-history clear" assert summary["payload"]["outgoing_saved"] == 1 assert summary["payload"]["raw"] == raw.to_dict() assert "other side cleared" not in summary["payload"]["meaning"] assert "does not identify who deleted them" in summary["payload"]["meaning"] deleted = [e for e in events if e["kind"] == "message.deleted"] assert len(deleted) == count assert all(e["payload"]["deleted_by"] is None for e in deleted) assert all(e["payload"]["deletion_time"] is None for e in deleted) assert all(e["payload"]["batch"]["hash"] == summary["hash"] for e in deleted) store.verify(vault.public_key) finally: store.close() > asyncio.run(scenario()) tools/test_deletion_semantics.py:52: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3.12/asyncio/runners.py:194: in run return runner.run(main) ^^^^^^^^^^^^^^^^ /usr/lib/python3.12/asyncio/runners.py:118: in run return self._loop.run_until_complete(task) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.12/asyncio/base_events.py:687: in run_until_complete return future.result() ^^^^^^^^^^^^^^^ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ async def scenario(): vault, store = Vault(tmp_path), Store(tmp_path) store.bind(vault) store.set_target(chat_id, "Synthetic evidence review", "private" if chat_id > 0 else "supergroup", True) collector = Collector(store, vault) collector.running = True ids = list(range(1, count + 1)) try: for mid in [*ids, 100]: store.append("message.new", {"text": f"Synthetic message {mid}", "outgoing": mid == 1, "sent_at": "2026-11-05T12:00:00+00:00", "edited_at": None}, chat_id, mid) raw = (types.UpdateDeleteMessages(messages=ids, pts=1, pts_count=count) if chat_id > 0 else types.UpdateDeleteChannelMessages(channel_id=555, messages=ids, pts=1, pts_count=count)) await collector.on_delete(SimpleNamespace(chat_id=None if chat_id > 0 else chat_id, deleted_ids=ids, original_update=raw)) assert store.message_state(chat_id, 100)["deleted"] is False events = list(store.all_events()) summaries = [e for e in events if e["kind"] in ("deletion.batch", "history.cleared")] assert len(summaries) == 1 summary = summaries[0] assert summary["kind"] == "deletion.batch", "A subset deletion is not a whole-history clear" assert summary["payload"]["outgoing_saved"] == 1 assert summary["payload"]["raw"] == raw.to_dict() assert "other side cleared" not in summary["payload"]["meaning"] > assert "does not identify who deleted them" in summary["payload"]["meaning"] E AssertionError: assert 'does not identify who deleted them' in 'Telegram reported several message IDs as deleted in one update.' tools/test_deletion_semantics.py:43: AssertionError ___ test_deletion_of_subset_keeps_actor_and_whole_history_unknown[10-55123] ____ tmp_path = PosixPath('/tmp/pytest-of-root/pytest-5/test_deletion_of_subset_keeps_4') chat_id = 55123, count = 10 @pytest.mark.parametrize("chat_id", [55123, -1000000000555]) @pytest.mark.parametrize("count", [2, 9, 10, 15]) def test_deletion_of_subset_keeps_actor_and_whole_history_unknown(tmp_path, chat_id, count): async def scenario(): vault, store = Vault(tmp_path), Store(tmp_path) store.bind(vault) store.set_target(chat_id, "Synthetic evidence review", "private" if chat_id > 0 else "supergroup", True) collector = Collector(store, vault) collector.running = True ids = list(range(1, count + 1)) try: for mid in [*ids, 100]: store.append("message.new", {"text": f"Synthetic message {mid}", "outgoing": mid == 1, "sent_at": "2026-11-05T12:00:00+00:00", "edited_at": None}, chat_id, mid) raw = (types.UpdateDeleteMessages(messages=ids, pts=1, pts_count=count) if chat_id > 0 else types.UpdateDeleteChannelMessages(channel_id=555, messages=ids, pts=1, pts_count=count)) await collector.on_delete(SimpleNamespace(chat_id=None if chat_id > 0 else chat_id, deleted_ids=ids, original_update=raw)) assert store.message_state(chat_id, 100)["deleted"] is False events = list(store.all_events()) summaries = [e for e in events if e["kind"] in ("deletion.batch", "history.cleared")] assert len(summaries) == 1 summary = summaries[0] assert summary["kind"] == "deletion.batch", "A subset deletion is not a whole-history clear" assert summary["payload"]["outgoing_saved"] == 1 assert summary["payload"]["raw"] == raw.to_dict() assert "other side cleared" not in summary["payload"]["meaning"] assert "does not identify who deleted them" in summary["payload"]["meaning"] deleted = [e for e in events if e["kind"] == "message.deleted"] assert len(deleted) == count assert all(e["payload"]["deleted_by"] is None for e in deleted) assert all(e["payload"]["deletion_time"] is None for e in deleted) assert all(e["payload"]["batch"]["hash"] == summary["hash"] for e in deleted) store.verify(vault.public_key) finally: store.close() > asyncio.run(scenario()) tools/test_deletion_semantics.py:52: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3.12/asyncio/runners.py:194: in run return runner.run(main) ^^^^^^^^^^^^^^^^ /usr/lib/python3.12/asyncio/runners.py:118: in run return self._loop.run_until_complete(task) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.12/asyncio/base_events.py:687: in run_until_complete return future.result() ^^^^^^^^^^^^^^^ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ async def scenario(): vault, store = Vault(tmp_path), Store(tmp_path) store.bind(vault) store.set_target(chat_id, "Synthetic evidence review", "private" if chat_id > 0 else "supergroup", True) collector = Collector(store, vault) collector.running = True ids = list(range(1, count + 1)) try: for mid in [*ids, 100]: store.append("message.new", {"text": f"Synthetic message {mid}", "outgoing": mid == 1, "sent_at": "2026-11-05T12:00:00+00:00", "edited_at": None}, chat_id, mid) raw = (types.UpdateDeleteMessages(messages=ids, pts=1, pts_count=count) if chat_id > 0 else types.UpdateDeleteChannelMessages(channel_id=555, messages=ids, pts=1, pts_count=count)) await collector.on_delete(SimpleNamespace(chat_id=None if chat_id > 0 else chat_id, deleted_ids=ids, original_update=raw)) assert store.message_state(chat_id, 100)["deleted"] is False events = list(store.all_events()) summaries = [e for e in events if e["kind"] in ("deletion.batch", "history.cleared")] assert len(summaries) == 1 summary = summaries[0] assert summary["kind"] == "deletion.batch", "A subset deletion is not a whole-history clear" assert summary["payload"]["outgoing_saved"] == 1 assert summary["payload"]["raw"] == raw.to_dict() assert "other side cleared" not in summary["payload"]["meaning"] > assert "does not identify who deleted them" in summary["payload"]["meaning"] E AssertionError: assert 'does not identify who deleted them' in 'Telegram reported several message IDs as deleted in one update.' tools/test_deletion_semantics.py:43: AssertionError _ test_deletion_of_subset_keeps_actor_and_whole_history_unknown[10--1000000000555] _ tmp_path = PosixPath('/tmp/pytest-of-root/pytest-5/test_deletion_of_subset_keeps_5') chat_id = -1000000000555, count = 10 @pytest.mark.parametrize("chat_id", [55123, -1000000000555]) @pytest.mark.parametrize("count", [2, 9, 10, 15]) def test_deletion_of_subset_keeps_actor_and_whole_history_unknown(tmp_path, chat_id, count): async def scenario(): vault, store = Vault(tmp_path), Store(tmp_path) store.bind(vault) store.set_target(chat_id, "Synthetic evidence review", "private" if chat_id > 0 else "supergroup", True) collector = Collector(store, vault) collector.running = True ids = list(range(1, count + 1)) try: for mid in [*ids, 100]: store.append("message.new", {"text": f"Synthetic message {mid}", "outgoing": mid == 1, "sent_at": "2026-11-05T12:00:00+00:00", "edited_at": None}, chat_id, mid) raw = (types.UpdateDeleteMessages(messages=ids, pts=1, pts_count=count) if chat_id > 0 else types.UpdateDeleteChannelMessages(channel_id=555, messages=ids, pts=1, pts_count=count)) await collector.on_delete(SimpleNamespace(chat_id=None if chat_id > 0 else chat_id, deleted_ids=ids, original_update=raw)) assert store.message_state(chat_id, 100)["deleted"] is False events = list(store.all_events()) summaries = [e for e in events if e["kind"] in ("deletion.batch", "history.cleared")] assert len(summaries) == 1 summary = summaries[0] assert summary["kind"] == "deletion.batch", "A subset deletion is not a whole-history clear" assert summary["payload"]["outgoing_saved"] == 1 assert summary["payload"]["raw"] == raw.to_dict() assert "other side cleared" not in summary["payload"]["meaning"] assert "does not identify who deleted them" in summary["payload"]["meaning"] deleted = [e for e in events if e["kind"] == "message.deleted"] assert len(deleted) == count assert all(e["payload"]["deleted_by"] is None for e in deleted) assert all(e["payload"]["deletion_time"] is None for e in deleted) assert all(e["payload"]["batch"]["hash"] == summary["hash"] for e in deleted) store.verify(vault.public_key) finally: store.close() > asyncio.run(scenario()) tools/test_deletion_semantics.py:52: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3.12/asyncio/runners.py:194: in run return runner.run(main) ^^^^^^^^^^^^^^^^ /usr/lib/python3.12/asyncio/runners.py:118: in run return self._loop.run_until_complete(task) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.12/asyncio/base_events.py:687: in run_until_complete return future.result() ^^^^^^^^^^^^^^^ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ async def scenario(): vault, store = Vault(tmp_path), Store(tmp_path) store.bind(vault) store.set_target(chat_id, "Synthetic evidence review", "private" if chat_id > 0 else "supergroup", True) collector = Collector(store, vault) collector.running = True ids = list(range(1, count + 1)) try: for mid in [*ids, 100]: store.append("message.new", {"text": f"Synthetic message {mid}", "outgoing": mid == 1, "sent_at": "2026-11-05T12:00:00+00:00", "edited_at": None}, chat_id, mid) raw = (types.UpdateDeleteMessages(messages=ids, pts=1, pts_count=count) if chat_id > 0 else types.UpdateDeleteChannelMessages(channel_id=555, messages=ids, pts=1, pts_count=count)) await collector.on_delete(SimpleNamespace(chat_id=None if chat_id > 0 else chat_id, deleted_ids=ids, original_update=raw)) assert store.message_state(chat_id, 100)["deleted"] is False events = list(store.all_events()) summaries = [e for e in events if e["kind"] in ("deletion.batch", "history.cleared")] assert len(summaries) == 1 summary = summaries[0] assert summary["kind"] == "deletion.batch", "A subset deletion is not a whole-history clear" assert summary["payload"]["outgoing_saved"] == 1 assert summary["payload"]["raw"] == raw.to_dict() assert "other side cleared" not in summary["payload"]["meaning"] > assert "does not identify who deleted them" in summary["payload"]["meaning"] E AssertionError: assert 'does not identify who deleted them' in 'Telegram reported several message IDs as deleted in one update.' tools/test_deletion_semantics.py:43: AssertionError ___ test_deletion_of_subset_keeps_actor_and_whole_history_unknown[15-55123] ____ tmp_path = PosixPath('/tmp/pytest-of-root/pytest-5/test_deletion_of_subset_keeps_6') chat_id = 55123, count = 15 @pytest.mark.parametrize("chat_id", [55123, -1000000000555]) @pytest.mark.parametrize("count", [2, 9, 10, 15]) def test_deletion_of_subset_keeps_actor_and_whole_history_unknown(tmp_path, chat_id, count): async def scenario(): vault, store = Vault(tmp_path), Store(tmp_path) store.bind(vault) store.set_target(chat_id, "Synthetic evidence review", "private" if chat_id > 0 else "supergroup", True) collector = Collector(store, vault) collector.running = True ids = list(range(1, count + 1)) try: for mid in [*ids, 100]: store.append("message.new", {"text": f"Synthetic message {mid}", "outgoing": mid == 1, "sent_at": "2026-11-05T12:00:00+00:00", "edited_at": None}, chat_id, mid) raw = (types.UpdateDeleteMessages(messages=ids, pts=1, pts_count=count) if chat_id > 0 else types.UpdateDeleteChannelMessages(channel_id=555, messages=ids, pts=1, pts_count=count)) await collector.on_delete(SimpleNamespace(chat_id=None if chat_id > 0 else chat_id, deleted_ids=ids, original_update=raw)) assert store.message_state(chat_id, 100)["deleted"] is False events = list(store.all_events()) summaries = [e for e in events if e["kind"] in ("deletion.batch", "history.cleared")] assert len(summaries) == 1 summary = summaries[0] assert summary["kind"] == "deletion.batch", "A subset deletion is not a whole-history clear" assert summary["payload"]["outgoing_saved"] == 1 assert summary["payload"]["raw"] == raw.to_dict() assert "other side cleared" not in summary["payload"]["meaning"] assert "does not identify who deleted them" in summary["payload"]["meaning"] deleted = [e for e in events if e["kind"] == "message.deleted"] assert len(deleted) == count assert all(e["payload"]["deleted_by"] is None for e in deleted) assert all(e["payload"]["deletion_time"] is None for e in deleted) assert all(e["payload"]["batch"]["hash"] == summary["hash"] for e in deleted) store.verify(vault.public_key) finally: store.close() > asyncio.run(scenario()) tools/test_deletion_semantics.py:52: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3.12/asyncio/runners.py:194: in run return runner.run(main) ^^^^^^^^^^^^^^^^ /usr/lib/python3.12/asyncio/runners.py:118: in run return self._loop.run_until_complete(task) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.12/asyncio/base_events.py:687: in run_until_complete return future.result() ^^^^^^^^^^^^^^^ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ async def scenario(): vault, store = Vault(tmp_path), Store(tmp_path) store.bind(vault) store.set_target(chat_id, "Synthetic evidence review", "private" if chat_id > 0 else "supergroup", True) collector = Collector(store, vault) collector.running = True ids = list(range(1, count + 1)) try: for mid in [*ids, 100]: store.append("message.new", {"text": f"Synthetic message {mid}", "outgoing": mid == 1, "sent_at": "2026-11-05T12:00:00+00:00", "edited_at": None}, chat_id, mid) raw = (types.UpdateDeleteMessages(messages=ids, pts=1, pts_count=count) if chat_id > 0 else types.UpdateDeleteChannelMessages(channel_id=555, messages=ids, pts=1, pts_count=count)) await collector.on_delete(SimpleNamespace(chat_id=None if chat_id > 0 else chat_id, deleted_ids=ids, original_update=raw)) assert store.message_state(chat_id, 100)["deleted"] is False events = list(store.all_events()) summaries = [e for e in events if e["kind"] in ("deletion.batch", "history.cleared")] assert len(summaries) == 1 summary = summaries[0] assert summary["kind"] == "deletion.batch", "A subset deletion is not a whole-history clear" assert summary["payload"]["outgoing_saved"] == 1 assert summary["payload"]["raw"] == raw.to_dict() assert "other side cleared" not in summary["payload"]["meaning"] > assert "does not identify who deleted them" in summary["payload"]["meaning"] E AssertionError: assert 'does not identify who deleted them' in 'Telegram reported several message IDs as deleted in one update.' tools/test_deletion_semantics.py:43: AssertionError _ test_deletion_of_subset_keeps_actor_and_whole_history_unknown[15--1000000000555] _ tmp_path = PosixPath('/tmp/pytest-of-root/pytest-5/test_deletion_of_subset_keeps_7') chat_id = -1000000000555, count = 15 @pytest.mark.parametrize("chat_id", [55123, -1000000000555]) @pytest.mark.parametrize("count", [2, 9, 10, 15]) def test_deletion_of_subset_keeps_actor_and_whole_history_unknown(tmp_path, chat_id, count): async def scenario(): vault, store = Vault(tmp_path), Store(tmp_path) store.bind(vault) store.set_target(chat_id, "Synthetic evidence review", "private" if chat_id > 0 else "supergroup", True) collector = Collector(store, vault) collector.running = True ids = list(range(1, count + 1)) try: for mid in [*ids, 100]: store.append("message.new", {"text": f"Synthetic message {mid}", "outgoing": mid == 1, "sent_at": "2026-11-05T12:00:00+00:00", "edited_at": None}, chat_id, mid) raw = (types.UpdateDeleteMessages(messages=ids, pts=1, pts_count=count) if chat_id > 0 else types.UpdateDeleteChannelMessages(channel_id=555, messages=ids, pts=1, pts_count=count)) await collector.on_delete(SimpleNamespace(chat_id=None if chat_id > 0 else chat_id, deleted_ids=ids, original_update=raw)) assert store.message_state(chat_id, 100)["deleted"] is False events = list(store.all_events()) summaries = [e for e in events if e["kind"] in ("deletion.batch", "history.cleared")] assert len(summaries) == 1 summary = summaries[0] assert summary["kind"] == "deletion.batch", "A subset deletion is not a whole-history clear" assert summary["payload"]["outgoing_saved"] == 1 assert summary["payload"]["raw"] == raw.to_dict() assert "other side cleared" not in summary["payload"]["meaning"] assert "does not identify who deleted them" in summary["payload"]["meaning"] deleted = [e for e in events if e["kind"] == "message.deleted"] assert len(deleted) == count assert all(e["payload"]["deleted_by"] is None for e in deleted) assert all(e["payload"]["deletion_time"] is None for e in deleted) assert all(e["payload"]["batch"]["hash"] == summary["hash"] for e in deleted) store.verify(vault.public_key) finally: store.close() > asyncio.run(scenario()) tools/test_deletion_semantics.py:52: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /usr/lib/python3.12/asyncio/runners.py:194: in run return runner.run(main) ^^^^^^^^^^^^^^^^ /usr/lib/python3.12/asyncio/runners.py:118: in run return self._loop.run_until_complete(task) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /usr/lib/python3.12/asyncio/base_events.py:687: in run_until_complete return future.result() ^^^^^^^^^^^^^^^ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ async def scenario(): vault, store = Vault(tmp_path), Store(tmp_path) store.bind(vault) store.set_target(chat_id, "Synthetic evidence review", "private" if chat_id > 0 else "supergroup", True) collector = Collector(store, vault) collector.running = True ids = list(range(1, count + 1)) try: for mid in [*ids, 100]: store.append("message.new", {"text": f"Synthetic message {mid}", "outgoing": mid == 1, "sent_at": "2026-11-05T12:00:00+00:00", "edited_at": None}, chat_id, mid) raw = (types.UpdateDeleteMessages(messages=ids, pts=1, pts_count=count) if chat_id > 0 else types.UpdateDeleteChannelMessages(channel_id=555, messages=ids, pts=1, pts_count=count)) await collector.on_delete(SimpleNamespace(chat_id=None if chat_id > 0 else chat_id, deleted_ids=ids, original_update=raw)) assert store.message_state(chat_id, 100)["deleted"] is False events = list(store.all_events()) summaries = [e for e in events if e["kind"] in ("deletion.batch", "history.cleared")] assert len(summaries) == 1 summary = summaries[0] assert summary["kind"] == "deletion.batch", "A subset deletion is not a whole-history clear" assert summary["payload"]["outgoing_saved"] == 1 assert summary["payload"]["raw"] == raw.to_dict() assert "other side cleared" not in summary["payload"]["meaning"] > assert "does not identify who deleted them" in summary["payload"]["meaning"] E AssertionError: assert 'does not identify who deleted them' in 'Telegram reported several message IDs as deleted in one update.' tools/test_deletion_semantics.py:43: AssertionError _______ test_the_dossier_counts_clients_sticker_sets_and_prepared_media ________ tmp_path = PosixPath('/tmp/pytest-of-root/pytest-5/test_the_dossier_counts_client0') def test_the_dossier_counts_clients_sticker_sets_and_prepared_media(tmp_path): vault, store = Vault(tmp_path), Store(tmp_path) store.bind(vault) try: store.set_target(CHAT, "Fictional payouts", "group", True) for number, raw in enumerate([video("round_1.mp4", (384, 384)), video(None, (384, 384)), video(None, (384, 384), sent="2026-11-02T12:00:00+00:00", uploaded="2026-11-02T06:00:00+00:00")], 1): store.append("message.new", {"text": "", "sender_id": PERSON, "sent_at": raw["date"], "sender_observation": {"id": PERSON, "display_name": "Admin"}, "raw": raw}, CHAT, number) built = dossier.build(store, CHAT) person = next(p for p in built["people"] if p["id"] == PERSON) assert {item["value"] for item in person["clients"]["observed"]} == {"Telegram Desktop", "Telegram for Android"} > assert "Metadata hypothesis about the client that encoded the file" in person["clients"]["meaning"] E assert 'Metadata hypothesis about the client that encoded the file' in "Client that encoded the file, read from the file's own metadata. A forwarded or re-uploaded file carries the encoder of whoever made it first." tools/test_device_attribution.py:104: AssertionError _______ test_choices_do_not_upgrade_facts_or_claim_safeguards_were_used ________ def test_choices_do_not_upgrade_facts_or_claim_safeguards_were_used(): context = {'event_count': 5, 'digest': {'trust_signals': {'tdx': 1}}} expected = case_assessment.journal(context, {}) choice = {'jurisdiction': 'US', 'include_methods': True} actual = case_assessment.journal({**context, 'options': {'jurisdiction_guidance': choice}}, {}) assert actual['checks'] == expected['checks'] assert actual['independent_review'] == 'not_performed' data = actual['jurisdiction_guidance'] assert len(data['safeguards']) == 7 > assert 'does not mean a measure was used or verified' in guide.html(data) E assert 'does not mean a measure was used or verified' in '

Jurisdiction guidance<...ed by a separate party takes the host and hypervisor out of the operator's control.

' E + where '

Jurisdiction guidance<...ed by a separate party takes the host and hypervisor out of the operator's control.

' = ({'format': 'tgwitness-jurisdiction-guidance-v1', 'language': 'en', 'catalog_version': '2026-11-06.1', 'catalog_sha256': 'd77d49d1d9f26dcf70906ff42a13b8e36d463d78d3dccbee82884477b96fe1d2', ...}) E + where = guide.html tools/test_jurisdiction_guidance.py:55: AssertionError ____________ test_outbox_read_watermark_does_not_identify_a_person _____________ def test_outbox_read_watermark_does_not_identify_a_person(): class UpdateReadHistoryOutbox: pass update = UpdateReadHistoryOutbox() update.peer, update.max_id = NS(user_id=7000000001), 1500 record = raw_updates.record_for(update, now=2.0) assert record["kind"] == "forensics.outbox_read_watermark" assert record["payload"]["max_id"] == 1500 > assert "does not identify" in record["payload"]["meaning"] E AssertionError: assert 'does not identify' in 'Observed outgoing read watermark.' tools/test_mtproto_forensics.py:290: AssertionError ______________________ test_pdf_html_and_svg_outputs[en] _______________________ tmp_path = PosixPath('/tmp/pytest-of-root/pytest-5/test_pdf_html_and_svg_outputs_0') lang = 'en' @pytest.mark.parametrize('lang', LANGUAGES) def test_pdf_html_and_svg_outputs(tmp_path, lang): package, events = fixture(tmp_path) out = tmp_path / ('narrative-' + lang) model = generate(package, out, lang=lang) assert (out / 'narrative.pdf').read_bytes().startswith(b'%PDF-') assert len(list((out / 'diagrams').glob('*.svg'))) == 4 assert json.loads((out / 'narrative.json').read_text(encoding='utf-8')) == model html = (out / 'narrative.html').read_text(encoding='utf-8') assert events[-1]['hash'] in html > assert 'machine-assisted, not reviewed' == model['translation_review'] ^^^^^^^^^^^^^^^^^^^^^^^^^^^ E KeyError: 'translation_review' tools/test_narrative.py:83: KeyError ______________________ test_pdf_html_and_svg_outputs[de] _______________________ tmp_path = PosixPath('/tmp/pytest-of-root/pytest-5/test_pdf_html_and_svg_outputs_1') lang = 'de' @pytest.mark.parametrize('lang', LANGUAGES) def test_pdf_html_and_svg_outputs(tmp_path, lang): package, events = fixture(tmp_path) out = tmp_path / ('narrative-' + lang) model = generate(package, out, lang=lang) assert (out / 'narrative.pdf').read_bytes().startswith(b'%PDF-') assert len(list((out / 'diagrams').glob('*.svg'))) == 4 assert json.loads((out / 'narrative.json').read_text(encoding='utf-8')) == model html = (out / 'narrative.html').read_text(encoding='utf-8') assert events[-1]['hash'] in html > assert 'machine-assisted, not reviewed' == model['translation_review'] ^^^^^^^^^^^^^^^^^^^^^^^^^^^ E KeyError: 'translation_review' tools/test_narrative.py:83: KeyError ______________________ test_pdf_html_and_svg_outputs[fr] _______________________ tmp_path = PosixPath('/tmp/pytest-of-root/pytest-5/test_pdf_html_and_svg_outputs_2') lang = 'fr' @pytest.mark.parametrize('lang', LANGUAGES) def test_pdf_html_and_svg_outputs(tmp_path, lang): package, events = fixture(tmp_path) out = tmp_path / ('narrative-' + lang) model = generate(package, out, lang=lang) assert (out / 'narrative.pdf').read_bytes().startswith(b'%PDF-') assert len(list((out / 'diagrams').glob('*.svg'))) == 4 assert json.loads((out / 'narrative.json').read_text(encoding='utf-8')) == model html = (out / 'narrative.html').read_text(encoding='utf-8') assert events[-1]['hash'] in html > assert 'machine-assisted, not reviewed' == model['translation_review'] ^^^^^^^^^^^^^^^^^^^^^^^^^^^ E KeyError: 'translation_review' tools/test_narrative.py:83: KeyError ______________________ test_pdf_html_and_svg_outputs[es] _______________________ tmp_path = PosixPath('/tmp/pytest-of-root/pytest-5/test_pdf_html_and_svg_outputs_3') lang = 'es' @pytest.mark.parametrize('lang', LANGUAGES) def test_pdf_html_and_svg_outputs(tmp_path, lang): package, events = fixture(tmp_path) out = tmp_path / ('narrative-' + lang) model = generate(package, out, lang=lang) assert (out / 'narrative.pdf').read_bytes().startswith(b'%PDF-') assert len(list((out / 'diagrams').glob('*.svg'))) == 4 assert json.loads((out / 'narrative.json').read_text(encoding='utf-8')) == model html = (out / 'narrative.html').read_text(encoding='utf-8') assert events[-1]['hash'] in html > assert 'machine-assisted, not reviewed' == model['translation_review'] ^^^^^^^^^^^^^^^^^^^^^^^^^^^ E KeyError: 'translation_review' tools/test_narrative.py:83: KeyError ______________________ test_pdf_html_and_svg_outputs[it] _______________________ tmp_path = PosixPath('/tmp/pytest-of-root/pytest-5/test_pdf_html_and_svg_outputs_4') lang = 'it' @pytest.mark.parametrize('lang', LANGUAGES) def test_pdf_html_and_svg_outputs(tmp_path, lang): package, events = fixture(tmp_path) out = tmp_path / ('narrative-' + lang) model = generate(package, out, lang=lang) assert (out / 'narrative.pdf').read_bytes().startswith(b'%PDF-') assert len(list((out / 'diagrams').glob('*.svg'))) == 4 assert json.loads((out / 'narrative.json').read_text(encoding='utf-8')) == model html = (out / 'narrative.html').read_text(encoding='utf-8') assert events[-1]['hash'] in html > assert 'machine-assisted, not reviewed' == model['translation_review'] ^^^^^^^^^^^^^^^^^^^^^^^^^^^ E KeyError: 'translation_review' tools/test_narrative.py:83: KeyError ______________________ test_pdf_html_and_svg_outputs[pt] _______________________ tmp_path = PosixPath('/tmp/pytest-of-root/pytest-5/test_pdf_html_and_svg_outputs_5') lang = 'pt' @pytest.mark.parametrize('lang', LANGUAGES) def test_pdf_html_and_svg_outputs(tmp_path, lang): package, events = fixture(tmp_path) out = tmp_path / ('narrative-' + lang) model = generate(package, out, lang=lang) assert (out / 'narrative.pdf').read_bytes().startswith(b'%PDF-') assert len(list((out / 'diagrams').glob('*.svg'))) == 4 assert json.loads((out / 'narrative.json').read_text(encoding='utf-8')) == model html = (out / 'narrative.html').read_text(encoding='utf-8') assert events[-1]['hash'] in html > assert 'machine-assisted, not reviewed' == model['translation_review'] ^^^^^^^^^^^^^^^^^^^^^^^^^^^ E KeyError: 'translation_review' tools/test_narrative.py:83: KeyError ______________________ test_pdf_html_and_svg_outputs[nl] _______________________ tmp_path = PosixPath('/tmp/pytest-of-root/pytest-5/test_pdf_html_and_svg_outputs_6') lang = 'nl' @pytest.mark.parametrize('lang', LANGUAGES) def test_pdf_html_and_svg_outputs(tmp_path, lang): package, events = fixture(tmp_path) out = tmp_path / ('narrative-' + lang) model = generate(package, out, lang=lang) assert (out / 'narrative.pdf').read_bytes().startswith(b'%PDF-') assert len(list((out / 'diagrams').glob('*.svg'))) == 4 assert json.loads((out / 'narrative.json').read_text(encoding='utf-8')) == model html = (out / 'narrative.html').read_text(encoding='utf-8') assert events[-1]['hash'] in html > assert 'machine-assisted, not reviewed' == model['translation_review'] ^^^^^^^^^^^^^^^^^^^^^^^^^^^ E KeyError: 'translation_review' tools/test_narrative.py:83: KeyError ______________________ test_pdf_html_and_svg_outputs[pl] _______________________ tmp_path = PosixPath('/tmp/pytest-of-root/pytest-5/test_pdf_html_and_svg_outputs_7') lang = 'pl' @pytest.mark.parametrize('lang', LANGUAGES) def test_pdf_html_and_svg_outputs(tmp_path, lang): package, events = fixture(tmp_path) out = tmp_path / ('narrative-' + lang) model = generate(package, out, lang=lang) assert (out / 'narrative.pdf').read_bytes().startswith(b'%PDF-') assert len(list((out / 'diagrams').glob('*.svg'))) == 4 assert json.loads((out / 'narrative.json').read_text(encoding='utf-8')) == model html = (out / 'narrative.html').read_text(encoding='utf-8') assert events[-1]['hash'] in html > assert 'machine-assisted, not reviewed' == model['translation_review'] ^^^^^^^^^^^^^^^^^^^^^^^^^^^ E KeyError: 'translation_review' tools/test_narrative.py:83: KeyError ______________________ test_pdf_html_and_svg_outputs[cs] _______________________ tmp_path = PosixPath('/tmp/pytest-of-root/pytest-5/test_pdf_html_and_svg_outputs_8') lang = 'cs' @pytest.mark.parametrize('lang', LANGUAGES) def test_pdf_html_and_svg_outputs(tmp_path, lang): package, events = fixture(tmp_path) out = tmp_path / ('narrative-' + lang) model = generate(package, out, lang=lang) assert (out / 'narrative.pdf').read_bytes().startswith(b'%PDF-') assert len(list((out / 'diagrams').glob('*.svg'))) == 4 assert json.loads((out / 'narrative.json').read_text(encoding='utf-8')) == model html = (out / 'narrative.html').read_text(encoding='utf-8') assert events[-1]['hash'] in html > assert 'machine-assisted, not reviewed' == model['translation_review'] ^^^^^^^^^^^^^^^^^^^^^^^^^^^ E KeyError: 'translation_review' tools/test_narrative.py:83: KeyError ______________________ test_pdf_html_and_svg_outputs[sk] _______________________ tmp_path = PosixPath('/tmp/pytest-of-root/pytest-5/test_pdf_html_and_svg_outputs_9') lang = 'sk' @pytest.mark.parametrize('lang', LANGUAGES) def test_pdf_html_and_svg_outputs(tmp_path, lang): package, events = fixture(tmp_path) out = tmp_path / ('narrative-' + lang) model = generate(package, out, lang=lang) assert (out / 'narrative.pdf').read_bytes().startswith(b'%PDF-') assert len(list((out / 'diagrams').glob('*.svg'))) == 4 assert json.loads((out / 'narrative.json').read_text(encoding='utf-8')) == model html = (out / 'narrative.html').read_text(encoding='utf-8') assert events[-1]['hash'] in html > assert 'machine-assisted, not reviewed' == model['translation_review'] ^^^^^^^^^^^^^^^^^^^^^^^^^^^ E KeyError: 'translation_review' tools/test_narrative.py:83: KeyError ______________________ test_pdf_html_and_svg_outputs[uk] _______________________ tmp_path = PosixPath('/tmp/pytest-of-root/pytest-5/test_pdf_html_and_svg_outputs_10') lang = 'uk' @pytest.mark.parametrize('lang', LANGUAGES) def test_pdf_html_and_svg_outputs(tmp_path, lang): package, events = fixture(tmp_path) out = tmp_path / ('narrative-' + lang) model = generate(package, out, lang=lang) assert (out / 'narrative.pdf').read_bytes().startswith(b'%PDF-') assert len(list((out / 'diagrams').glob('*.svg'))) == 4 assert json.loads((out / 'narrative.json').read_text(encoding='utf-8')) == model html = (out / 'narrative.html').read_text(encoding='utf-8') assert events[-1]['hash'] in html > assert 'machine-assisted, not reviewed' == model['translation_review'] ^^^^^^^^^^^^^^^^^^^^^^^^^^^ E KeyError: 'translation_review' tools/test_narrative.py:83: KeyError ______________________ test_pdf_html_and_svg_outputs[ro] _______________________ tmp_path = PosixPath('/tmp/pytest-of-root/pytest-5/test_pdf_html_and_svg_outputs_11') lang = 'ro' @pytest.mark.parametrize('lang', LANGUAGES) def test_pdf_html_and_svg_outputs(tmp_path, lang): package, events = fixture(tmp_path) out = tmp_path / ('narrative-' + lang) model = generate(package, out, lang=lang) assert (out / 'narrative.pdf').read_bytes().startswith(b'%PDF-') assert len(list((out / 'diagrams').glob('*.svg'))) == 4 assert json.loads((out / 'narrative.json').read_text(encoding='utf-8')) == model html = (out / 'narrative.html').read_text(encoding='utf-8') assert events[-1]['hash'] in html > assert 'machine-assisted, not reviewed' == model['translation_review'] ^^^^^^^^^^^^^^^^^^^^^^^^^^^ E KeyError: 'translation_review' tools/test_narrative.py:83: KeyError ______________________ test_pdf_html_and_svg_outputs[bg] _______________________ tmp_path = PosixPath('/tmp/pytest-of-root/pytest-5/test_pdf_html_and_svg_outputs_12') lang = 'bg' @pytest.mark.parametrize('lang', LANGUAGES) def test_pdf_html_and_svg_outputs(tmp_path, lang): package, events = fixture(tmp_path) out = tmp_path / ('narrative-' + lang) model = generate(package, out, lang=lang) assert (out / 'narrative.pdf').read_bytes().startswith(b'%PDF-') assert len(list((out / 'diagrams').glob('*.svg'))) == 4 assert json.loads((out / 'narrative.json').read_text(encoding='utf-8')) == model html = (out / 'narrative.html').read_text(encoding='utf-8') assert events[-1]['hash'] in html > assert 'machine-assisted, not reviewed' == model['translation_review'] ^^^^^^^^^^^^^^^^^^^^^^^^^^^ E KeyError: 'translation_review' tools/test_narrative.py:83: KeyError ______________________ test_pdf_html_and_svg_outputs[hu] _______________________ tmp_path = PosixPath('/tmp/pytest-of-root/pytest-5/test_pdf_html_and_svg_outputs_13') lang = 'hu' @pytest.mark.parametrize('lang', LANGUAGES) def test_pdf_html_and_svg_outputs(tmp_path, lang): package, events = fixture(tmp_path) out = tmp_path / ('narrative-' + lang) model = generate(package, out, lang=lang) assert (out / 'narrative.pdf').read_bytes().startswith(b'%PDF-') assert len(list((out / 'diagrams').glob('*.svg'))) == 4 assert json.loads((out / 'narrative.json').read_text(encoding='utf-8')) == model html = (out / 'narrative.html').read_text(encoding='utf-8') assert events[-1]['hash'] in html > assert 'machine-assisted, not reviewed' == model['translation_review'] ^^^^^^^^^^^^^^^^^^^^^^^^^^^ E KeyError: 'translation_review' tools/test_narrative.py:83: KeyError ______________________ test_pdf_html_and_svg_outputs[el] _______________________ tmp_path = PosixPath('/tmp/pytest-of-root/pytest-5/test_pdf_html_and_svg_outputs_14') lang = 'el' @pytest.mark.parametrize('lang', LANGUAGES) def test_pdf_html_and_svg_outputs(tmp_path, lang): package, events = fixture(tmp_path) out = tmp_path / ('narrative-' + lang) model = generate(package, out, lang=lang) assert (out / 'narrative.pdf').read_bytes().startswith(b'%PDF-') assert len(list((out / 'diagrams').glob('*.svg'))) == 4 assert json.loads((out / 'narrative.json').read_text(encoding='utf-8')) == model html = (out / 'narrative.html').read_text(encoding='utf-8') assert events[-1]['hash'] in html > assert 'machine-assisted, not reviewed' == model['translation_review'] ^^^^^^^^^^^^^^^^^^^^^^^^^^^ E KeyError: 'translation_review' tools/test_narrative.py:83: KeyError ______________________ test_pdf_html_and_svg_outputs[sv] _______________________ tmp_path = PosixPath('/tmp/pytest-of-root/pytest-5/test_pdf_html_and_svg_outputs_15') lang = 'sv' @pytest.mark.parametrize('lang', LANGUAGES) def test_pdf_html_and_svg_outputs(tmp_path, lang): package, events = fixture(tmp_path) out = tmp_path / ('narrative-' + lang) model = generate(package, out, lang=lang) assert (out / 'narrative.pdf').read_bytes().startswith(b'%PDF-') assert len(list((out / 'diagrams').glob('*.svg'))) == 4 assert json.loads((out / 'narrative.json').read_text(encoding='utf-8')) == model html = (out / 'narrative.html').read_text(encoding='utf-8') assert events[-1]['hash'] in html > assert 'machine-assisted, not reviewed' == model['translation_review'] ^^^^^^^^^^^^^^^^^^^^^^^^^^^ E KeyError: 'translation_review' tools/test_narrative.py:83: KeyError ______________________ test_pdf_html_and_svg_outputs[da] _______________________ tmp_path = PosixPath('/tmp/pytest-of-root/pytest-5/test_pdf_html_and_svg_outputs_16') lang = 'da' @pytest.mark.parametrize('lang', LANGUAGES) def test_pdf_html_and_svg_outputs(tmp_path, lang): package, events = fixture(tmp_path) out = tmp_path / ('narrative-' + lang) model = generate(package, out, lang=lang) assert (out / 'narrative.pdf').read_bytes().startswith(b'%PDF-') assert len(list((out / 'diagrams').glob('*.svg'))) == 4 assert json.loads((out / 'narrative.json').read_text(encoding='utf-8')) == model html = (out / 'narrative.html').read_text(encoding='utf-8') assert events[-1]['hash'] in html > assert 'machine-assisted, not reviewed' == model['translation_review'] ^^^^^^^^^^^^^^^^^^^^^^^^^^^ E KeyError: 'translation_review' tools/test_narrative.py:83: KeyError ______________________ test_pdf_html_and_svg_outputs[fi] _______________________ tmp_path = PosixPath('/tmp/pytest-of-root/pytest-5/test_pdf_html_and_svg_outputs_17') lang = 'fi' @pytest.mark.parametrize('lang', LANGUAGES) def test_pdf_html_and_svg_outputs(tmp_path, lang): package, events = fixture(tmp_path) out = tmp_path / ('narrative-' + lang) model = generate(package, out, lang=lang) assert (out / 'narrative.pdf').read_bytes().startswith(b'%PDF-') assert len(list((out / 'diagrams').glob('*.svg'))) == 4 assert json.loads((out / 'narrative.json').read_text(encoding='utf-8')) == model html = (out / 'narrative.html').read_text(encoding='utf-8') assert events[-1]['hash'] in html > assert 'machine-assisted, not reviewed' == model['translation_review'] ^^^^^^^^^^^^^^^^^^^^^^^^^^^ E KeyError: 'translation_review' tools/test_narrative.py:83: KeyError ______________________ test_pdf_html_and_svg_outputs[no] _______________________ tmp_path = PosixPath('/tmp/pytest-of-root/pytest-5/test_pdf_html_and_svg_outputs_18') lang = 'no' @pytest.mark.parametrize('lang', LANGUAGES) def test_pdf_html_and_svg_outputs(tmp_path, lang): package, events = fixture(tmp_path) out = tmp_path / ('narrative-' + lang) model = generate(package, out, lang=lang) assert (out / 'narrative.pdf').read_bytes().startswith(b'%PDF-') assert len(list((out / 'diagrams').glob('*.svg'))) == 4 assert json.loads((out / 'narrative.json').read_text(encoding='utf-8')) == model html = (out / 'narrative.html').read_text(encoding='utf-8') assert events[-1]['hash'] in html > assert 'machine-assisted, not reviewed' == model['translation_review'] ^^^^^^^^^^^^^^^^^^^^^^^^^^^ E KeyError: 'translation_review' tools/test_narrative.py:83: KeyError ______________________ test_pdf_html_and_svg_outputs[lt] _______________________ tmp_path = PosixPath('/tmp/pytest-of-root/pytest-5/test_pdf_html_and_svg_outputs_19') lang = 'lt' @pytest.mark.parametrize('lang', LANGUAGES) def test_pdf_html_and_svg_outputs(tmp_path, lang): package, events = fixture(tmp_path) out = tmp_path / ('narrative-' + lang) model = generate(package, out, lang=lang) assert (out / 'narrative.pdf').read_bytes().startswith(b'%PDF-') assert len(list((out / 'diagrams').glob('*.svg'))) == 4 assert json.loads((out / 'narrative.json').read_text(encoding='utf-8')) == model html = (out / 'narrative.html').read_text(encoding='utf-8') assert events[-1]['hash'] in html > assert 'machine-assisted, not reviewed' == model['translation_review'] ^^^^^^^^^^^^^^^^^^^^^^^^^^^ E KeyError: 'translation_review' tools/test_narrative.py:83: KeyError ______________________ test_pdf_html_and_svg_outputs[lv] _______________________ tmp_path = PosixPath('/tmp/pytest-of-root/pytest-5/test_pdf_html_and_svg_outputs_20') lang = 'lv' @pytest.mark.parametrize('lang', LANGUAGES) def test_pdf_html_and_svg_outputs(tmp_path, lang): package, events = fixture(tmp_path) out = tmp_path / ('narrative-' + lang) model = generate(package, out, lang=lang) assert (out / 'narrative.pdf').read_bytes().startswith(b'%PDF-') assert len(list((out / 'diagrams').glob('*.svg'))) == 4 assert json.loads((out / 'narrative.json').read_text(encoding='utf-8')) == model html = (out / 'narrative.html').read_text(encoding='utf-8') assert events[-1]['hash'] in html > assert 'machine-assisted, not reviewed' == model['translation_review'] ^^^^^^^^^^^^^^^^^^^^^^^^^^^ E KeyError: 'translation_review' tools/test_narrative.py:83: KeyError ______________________ test_pdf_html_and_svg_outputs[et] _______________________ tmp_path = PosixPath('/tmp/pytest-of-root/pytest-5/test_pdf_html_and_svg_outputs_21') lang = 'et' @pytest.mark.parametrize('lang', LANGUAGES) def test_pdf_html_and_svg_outputs(tmp_path, lang): package, events = fixture(tmp_path) out = tmp_path / ('narrative-' + lang) model = generate(package, out, lang=lang) assert (out / 'narrative.pdf').read_bytes().startswith(b'%PDF-') assert len(list((out / 'diagrams').glob('*.svg'))) == 4 assert json.loads((out / 'narrative.json').read_text(encoding='utf-8')) == model html = (out / 'narrative.html').read_text(encoding='utf-8') assert events[-1]['hash'] in html > assert 'machine-assisted, not reviewed' == model['translation_review'] ^^^^^^^^^^^^^^^^^^^^^^^^^^^ E KeyError: 'translation_review' tools/test_narrative.py:83: KeyError ______________________ test_pdf_html_and_svg_outputs[tr] _______________________ tmp_path = PosixPath('/tmp/pytest-of-root/pytest-5/test_pdf_html_and_svg_outputs_22') lang = 'tr' @pytest.mark.parametrize('lang', LANGUAGES) def test_pdf_html_and_svg_outputs(tmp_path, lang): package, events = fixture(tmp_path) out = tmp_path / ('narrative-' + lang) model = generate(package, out, lang=lang) assert (out / 'narrative.pdf').read_bytes().startswith(b'%PDF-') assert len(list((out / 'diagrams').glob('*.svg'))) == 4 assert json.loads((out / 'narrative.json').read_text(encoding='utf-8')) == model html = (out / 'narrative.html').read_text(encoding='utf-8') assert events[-1]['hash'] in html > assert 'machine-assisted, not reviewed' == model['translation_review'] ^^^^^^^^^^^^^^^^^^^^^^^^^^^ E KeyError: 'translation_review' tools/test_narrative.py:83: KeyError ______________________ test_pdf_html_and_svg_outputs[ja] _______________________ tmp_path = PosixPath('/tmp/pytest-of-root/pytest-5/test_pdf_html_and_svg_outputs_23') lang = 'ja' @pytest.mark.parametrize('lang', LANGUAGES) def test_pdf_html_and_svg_outputs(tmp_path, lang): package, events = fixture(tmp_path) out = tmp_path / ('narrative-' + lang) model = generate(package, out, lang=lang) assert (out / 'narrative.pdf').read_bytes().startswith(b'%PDF-') assert len(list((out / 'diagrams').glob('*.svg'))) == 4 assert json.loads((out / 'narrative.json').read_text(encoding='utf-8')) == model html = (out / 'narrative.html').read_text(encoding='utf-8') assert events[-1]['hash'] in html > assert 'machine-assisted, not reviewed' == model['translation_review'] ^^^^^^^^^^^^^^^^^^^^^^^^^^^ E KeyError: 'translation_review' tools/test_narrative.py:83: KeyError ______________________ test_pdf_html_and_svg_outputs[zh] _______________________ tmp_path = PosixPath('/tmp/pytest-of-root/pytest-5/test_pdf_html_and_svg_outputs_24') lang = 'zh' @pytest.mark.parametrize('lang', LANGUAGES) def test_pdf_html_and_svg_outputs(tmp_path, lang): package, events = fixture(tmp_path) out = tmp_path / ('narrative-' + lang) model = generate(package, out, lang=lang) assert (out / 'narrative.pdf').read_bytes().startswith(b'%PDF-') assert len(list((out / 'diagrams').glob('*.svg'))) == 4 assert json.loads((out / 'narrative.json').read_text(encoding='utf-8')) == model html = (out / 'narrative.html').read_text(encoding='utf-8') assert events[-1]['hash'] in html > assert 'machine-assisted, not reviewed' == model['translation_review'] ^^^^^^^^^^^^^^^^^^^^^^^^^^^ E KeyError: 'translation_review' tools/test_narrative.py:83: KeyError ____________________ test_pdf_html_and_svg_outputs[zh-Hant] ____________________ tmp_path = PosixPath('/tmp/pytest-of-root/pytest-5/test_pdf_html_and_svg_outputs_25') lang = 'zh-Hant' @pytest.mark.parametrize('lang', LANGUAGES) def test_pdf_html_and_svg_outputs(tmp_path, lang): package, events = fixture(tmp_path) out = tmp_path / ('narrative-' + lang) model = generate(package, out, lang=lang) assert (out / 'narrative.pdf').read_bytes().startswith(b'%PDF-') assert len(list((out / 'diagrams').glob('*.svg'))) == 4 assert json.loads((out / 'narrative.json').read_text(encoding='utf-8')) == model html = (out / 'narrative.html').read_text(encoding='utf-8') assert events[-1]['hash'] in html > assert 'machine-assisted, not reviewed' == model['translation_review'] ^^^^^^^^^^^^^^^^^^^^^^^^^^^ E KeyError: 'translation_review' tools/test_narrative.py:83: KeyError ______________________ test_pdf_html_and_svg_outputs[ko] _______________________ tmp_path = PosixPath('/tmp/pytest-of-root/pytest-5/test_pdf_html_and_svg_outputs_26') lang = 'ko' @pytest.mark.parametrize('lang', LANGUAGES) def test_pdf_html_and_svg_outputs(tmp_path, lang): package, events = fixture(tmp_path) out = tmp_path / ('narrative-' + lang) model = generate(package, out, lang=lang) assert (out / 'narrative.pdf').read_bytes().startswith(b'%PDF-') assert len(list((out / 'diagrams').glob('*.svg'))) == 4 assert json.loads((out / 'narrative.json').read_text(encoding='utf-8')) == model html = (out / 'narrative.html').read_text(encoding='utf-8') assert events[-1]['hash'] in html > assert 'machine-assisted, not reviewed' == model['translation_review'] ^^^^^^^^^^^^^^^^^^^^^^^^^^^ E KeyError: 'translation_review' tools/test_narrative.py:83: KeyError ______________________ test_pdf_html_and_svg_outputs[ar] _______________________ tmp_path = PosixPath('/tmp/pytest-of-root/pytest-5/test_pdf_html_and_svg_outputs_27') lang = 'ar' @pytest.mark.parametrize('lang', LANGUAGES) def test_pdf_html_and_svg_outputs(tmp_path, lang): package, events = fixture(tmp_path) out = tmp_path / ('narrative-' + lang) model = generate(package, out, lang=lang) assert (out / 'narrative.pdf').read_bytes().startswith(b'%PDF-') assert len(list((out / 'diagrams').glob('*.svg'))) == 4 assert json.loads((out / 'narrative.json').read_text(encoding='utf-8')) == model html = (out / 'narrative.html').read_text(encoding='utf-8') assert events[-1]['hash'] in html > assert 'machine-assisted, not reviewed' == model['translation_review'] ^^^^^^^^^^^^^^^^^^^^^^^^^^^ E KeyError: 'translation_review' tools/test_narrative.py:83: KeyError ______________________ test_pdf_html_and_svg_outputs[he] _______________________ tmp_path = PosixPath('/tmp/pytest-of-root/pytest-5/test_pdf_html_and_svg_outputs_28') lang = 'he' @pytest.mark.parametrize('lang', LANGUAGES) def test_pdf_html_and_svg_outputs(tmp_path, lang): package, events = fixture(tmp_path) out = tmp_path / ('narrative-' + lang) model = generate(package, out, lang=lang) assert (out / 'narrative.pdf').read_bytes().startswith(b'%PDF-') assert len(list((out / 'diagrams').glob('*.svg'))) == 4 assert json.loads((out / 'narrative.json').read_text(encoding='utf-8')) == model html = (out / 'narrative.html').read_text(encoding='utf-8') assert events[-1]['hash'] in html > assert 'machine-assisted, not reviewed' == model['translation_review'] ^^^^^^^^^^^^^^^^^^^^^^^^^^^ E KeyError: 'translation_review' tools/test_narrative.py:83: KeyError ______________________ test_pdf_html_and_svg_outputs[fa] _______________________ tmp_path = PosixPath('/tmp/pytest-of-root/pytest-5/test_pdf_html_and_svg_outputs_29') lang = 'fa' @pytest.mark.parametrize('lang', LANGUAGES) def test_pdf_html_and_svg_outputs(tmp_path, lang): package, events = fixture(tmp_path) out = tmp_path / ('narrative-' + lang) model = generate(package, out, lang=lang) assert (out / 'narrative.pdf').read_bytes().startswith(b'%PDF-') assert len(list((out / 'diagrams').glob('*.svg'))) == 4 assert json.loads((out / 'narrative.json').read_text(encoding='utf-8')) == model html = (out / 'narrative.html').read_text(encoding='utf-8') assert events[-1]['hash'] in html > assert 'machine-assisted, not reviewed' == model['translation_review'] ^^^^^^^^^^^^^^^^^^^^^^^^^^^ E KeyError: 'translation_review' tools/test_narrative.py:83: KeyError ______________________ test_pdf_html_and_svg_outputs[hi] _______________________ tmp_path = PosixPath('/tmp/pytest-of-root/pytest-5/test_pdf_html_and_svg_outputs_30') lang = 'hi' @pytest.mark.parametrize('lang', LANGUAGES) def test_pdf_html_and_svg_outputs(tmp_path, lang): package, events = fixture(tmp_path) out = tmp_path / ('narrative-' + lang) model = generate(package, out, lang=lang) assert (out / 'narrative.pdf').read_bytes().startswith(b'%PDF-') assert len(list((out / 'diagrams').glob('*.svg'))) == 4 assert json.loads((out / 'narrative.json').read_text(encoding='utf-8')) == model html = (out / 'narrative.html').read_text(encoding='utf-8') assert events[-1]['hash'] in html > assert 'machine-assisted, not reviewed' == model['translation_review'] ^^^^^^^^^^^^^^^^^^^^^^^^^^^ E KeyError: 'translation_review' tools/test_narrative.py:83: KeyError ______________________ test_pdf_html_and_svg_outputs[ur] _______________________ tmp_path = PosixPath('/tmp/pytest-of-root/pytest-5/test_pdf_html_and_svg_outputs_31') lang = 'ur' @pytest.mark.parametrize('lang', LANGUAGES) def test_pdf_html_and_svg_outputs(tmp_path, lang): package, events = fixture(tmp_path) out = tmp_path / ('narrative-' + lang) model = generate(package, out, lang=lang) assert (out / 'narrative.pdf').read_bytes().startswith(b'%PDF-') assert len(list((out / 'diagrams').glob('*.svg'))) == 4 assert json.loads((out / 'narrative.json').read_text(encoding='utf-8')) == model html = (out / 'narrative.html').read_text(encoding='utf-8') assert events[-1]['hash'] in html > assert 'machine-assisted, not reviewed' == model['translation_review'] ^^^^^^^^^^^^^^^^^^^^^^^^^^^ E KeyError: 'translation_review' tools/test_narrative.py:83: KeyError ______________________ test_pdf_html_and_svg_outputs[bn] _______________________ tmp_path = PosixPath('/tmp/pytest-of-root/pytest-5/test_pdf_html_and_svg_outputs_32') lang = 'bn' @pytest.mark.parametrize('lang', LANGUAGES) def test_pdf_html_and_svg_outputs(tmp_path, lang): package, events = fixture(tmp_path) out = tmp_path / ('narrative-' + lang) model = generate(package, out, lang=lang) assert (out / 'narrative.pdf').read_bytes().startswith(b'%PDF-') assert len(list((out / 'diagrams').glob('*.svg'))) == 4 assert json.loads((out / 'narrative.json').read_text(encoding='utf-8')) == model html = (out / 'narrative.html').read_text(encoding='utf-8') assert events[-1]['hash'] in html > assert 'machine-assisted, not reviewed' == model['translation_review'] ^^^^^^^^^^^^^^^^^^^^^^^^^^^ E KeyError: 'translation_review' tools/test_narrative.py:83: KeyError ______________________ test_pdf_html_and_svg_outputs[id] _______________________ tmp_path = PosixPath('/tmp/pytest-of-root/pytest-5/test_pdf_html_and_svg_outputs_33') lang = 'id' @pytest.mark.parametrize('lang', LANGUAGES) def test_pdf_html_and_svg_outputs(tmp_path, lang): package, events = fixture(tmp_path) out = tmp_path / ('narrative-' + lang) model = generate(package, out, lang=lang) assert (out / 'narrative.pdf').read_bytes().startswith(b'%PDF-') assert len(list((out / 'diagrams').glob('*.svg'))) == 4 assert json.loads((out / 'narrative.json').read_text(encoding='utf-8')) == model html = (out / 'narrative.html').read_text(encoding='utf-8') assert events[-1]['hash'] in html > assert 'machine-assisted, not reviewed' == model['translation_review'] ^^^^^^^^^^^^^^^^^^^^^^^^^^^ E KeyError: 'translation_review' tools/test_narrative.py:83: KeyError ______________________ test_pdf_html_and_svg_outputs[ms] _______________________ tmp_path = PosixPath('/tmp/pytest-of-root/pytest-5/test_pdf_html_and_svg_outputs_34') lang = 'ms' @pytest.mark.parametrize('lang', LANGUAGES) def test_pdf_html_and_svg_outputs(tmp_path, lang): package, events = fixture(tmp_path) out = tmp_path / ('narrative-' + lang) model = generate(package, out, lang=lang) assert (out / 'narrative.pdf').read_bytes().startswith(b'%PDF-') assert len(list((out / 'diagrams').glob('*.svg'))) == 4 assert json.loads((out / 'narrative.json').read_text(encoding='utf-8')) == model html = (out / 'narrative.html').read_text(encoding='utf-8') assert events[-1]['hash'] in html > assert 'machine-assisted, not reviewed' == model['translation_review'] ^^^^^^^^^^^^^^^^^^^^^^^^^^^ E KeyError: 'translation_review' tools/test_narrative.py:83: KeyError ______________________ test_pdf_html_and_svg_outputs[vi] _______________________ tmp_path = PosixPath('/tmp/pytest-of-root/pytest-5/test_pdf_html_and_svg_outputs_35') lang = 'vi' @pytest.mark.parametrize('lang', LANGUAGES) def test_pdf_html_and_svg_outputs(tmp_path, lang): package, events = fixture(tmp_path) out = tmp_path / ('narrative-' + lang) model = generate(package, out, lang=lang) assert (out / 'narrative.pdf').read_bytes().startswith(b'%PDF-') assert len(list((out / 'diagrams').glob('*.svg'))) == 4 assert json.loads((out / 'narrative.json').read_text(encoding='utf-8')) == model html = (out / 'narrative.html').read_text(encoding='utf-8') assert events[-1]['hash'] in html > assert 'machine-assisted, not reviewed' == model['translation_review'] ^^^^^^^^^^^^^^^^^^^^^^^^^^^ E KeyError: 'translation_review' tools/test_narrative.py:83: KeyError ______________________ test_pdf_html_and_svg_outputs[th] _______________________ tmp_path = PosixPath('/tmp/pytest-of-root/pytest-5/test_pdf_html_and_svg_outputs_36') lang = 'th' @pytest.mark.parametrize('lang', LANGUAGES) def test_pdf_html_and_svg_outputs(tmp_path, lang): package, events = fixture(tmp_path) out = tmp_path / ('narrative-' + lang) model = generate(package, out, lang=lang) assert (out / 'narrative.pdf').read_bytes().startswith(b'%PDF-') assert len(list((out / 'diagrams').glob('*.svg'))) == 4 assert json.loads((out / 'narrative.json').read_text(encoding='utf-8')) == model html = (out / 'narrative.html').read_text(encoding='utf-8') assert events[-1]['hash'] in html > assert 'machine-assisted, not reviewed' == model['translation_review'] ^^^^^^^^^^^^^^^^^^^^^^^^^^^ E KeyError: 'translation_review' tools/test_narrative.py:83: KeyError ______________________ test_pdf_html_and_svg_outputs[uz] _______________________ tmp_path = PosixPath('/tmp/pytest-of-root/pytest-5/test_pdf_html_and_svg_outputs_37') lang = 'uz' @pytest.mark.parametrize('lang', LANGUAGES) def test_pdf_html_and_svg_outputs(tmp_path, lang): package, events = fixture(tmp_path) out = tmp_path / ('narrative-' + lang) model = generate(package, out, lang=lang) assert (out / 'narrative.pdf').read_bytes().startswith(b'%PDF-') assert len(list((out / 'diagrams').glob('*.svg'))) == 4 assert json.loads((out / 'narrative.json').read_text(encoding='utf-8')) == model html = (out / 'narrative.html').read_text(encoding='utf-8') assert events[-1]['hash'] in html > assert 'machine-assisted, not reviewed' == model['translation_review'] ^^^^^^^^^^^^^^^^^^^^^^^^^^^ E KeyError: 'translation_review' tools/test_narrative.py:83: KeyError ______________________ test_pdf_html_and_svg_outputs[ru] _______________________ tmp_path = PosixPath('/tmp/pytest-of-root/pytest-5/test_pdf_html_and_svg_outputs_38') lang = 'ru' @pytest.mark.parametrize('lang', LANGUAGES) def test_pdf_html_and_svg_outputs(tmp_path, lang): package, events = fixture(tmp_path) out = tmp_path / ('narrative-' + lang) model = generate(package, out, lang=lang) assert (out / 'narrative.pdf').read_bytes().startswith(b'%PDF-') assert len(list((out / 'diagrams').glob('*.svg'))) == 4 assert json.loads((out / 'narrative.json').read_text(encoding='utf-8')) == model html = (out / 'narrative.html').read_text(encoding='utf-8') assert events[-1]['hash'] in html > assert 'machine-assisted, not reviewed' == model['translation_review'] ^^^^^^^^^^^^^^^^^^^^^^^^^^^ E KeyError: 'translation_review' tools/test_narrative.py:83: KeyError _______________ test_jurisdictions_change_only_the_terms_section _______________ tmp_path = PosixPath('/tmp/pytest-of-root/pytest-5/test_jurisdictions_change_only0') def test_jurisdictions_change_only_the_terms_section(tmp_path): package, events = fixture(tmp_path) model = build(events, verify_bundle(package)) model['package_sha256'] = 'a' * 64 text = Texts('de') pictures = diagrams(model, text) rendered = [html_report(model, text, pictures, jurisdiction(code)) for code in ('DE', 'AT', 'CH')] assert len(set(rendered)) == 3 stripped = [re.sub(r'
.*?
', '', h) for h in rendered] > assert len(set(stripped)) == 1 E assert 3 == 1 E + where 3 = len({' return io.open(self, mode, buffering, encoding, errors, newline) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ E FileNotFoundError: [Errno 2] No such file or directory: '/workspace/qa/src/23c7cc65e776bca40b989ff73d9d2a438954604e/tgwitness/narrative/review-policy.json' /usr/lib/python3.12/pathlib.py:1015: FileNotFoundError __________________ test_golden_model_is_language_independent ___________________ def test_golden_model_is_language_independent(): source = Path(__file__).parent / 'fixtures/narrative-events.json' events = json.loads(source.read_text(encoding='utf-8')) result = {'fingerprint': 'synthetic-key', 'events': len(events), 'head_hash': events[-1]['hash']} actual = build(events, result) expected = json.loads(source.with_name('narrative-golden.json').read_text(encoding='utf-8')) > assert actual == expected E AssertionError: assert {'format': 't...e': None, ...} == {'format': 't...e': None, ...} E E Omitting 6 identical items, use -vv to show E Differing items: E {'limits': [{'template_key': 'limit.truth', 'params': {}}]} != {'limits': [{'template_key': 'limit.truth', 'params': {}}, {'template_key': 'limit.review', 'params': {}}]} E Right contains 1 more item: E {'translation_review': 'machine-assisted, not reviewed'} E Use -v to get more diff tools/test_narrative.py:150: AssertionError _ test_optional_diagrams_cannot_hide_assurance_limits_or_references[selected0] _ tmp_path = PosixPath('/tmp/pytest-of-root/pytest-5/test_optional_diagrams_cannot_0') selected = [] @pytest.mark.parametrize('selected', [[], ['timeline'], ['ladder', 'files']]) def test_optional_diagrams_cannot_hide_assurance_limits_or_references(tmp_path, selected): package, events = fixture(tmp_path) out = tmp_path / 'html' model = cli.generate(package, out, outputs=['html'], diagrams=selected) html = (out / 'narrative.html').read_text(encoding='utf-8') assert html.count(' assert text('heading.limits') in html and text('limit.review') in html ^^^^^^^^^^^^^^^^^^^^ tools/test_narrative_config.py:111: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = key = 'limit.review', params = {} def __call__(self, key, **params): > nodes = parse(self.values[key]) ^^^^^^^^^^^^^^^^ E KeyError: 'limit.review' tgwitness/narrative/text.py:138: KeyError _ test_optional_diagrams_cannot_hide_assurance_limits_or_references[selected1] _ tmp_path = PosixPath('/tmp/pytest-of-root/pytest-5/test_optional_diagrams_cannot_1') selected = ['timeline'] @pytest.mark.parametrize('selected', [[], ['timeline'], ['ladder', 'files']]) def test_optional_diagrams_cannot_hide_assurance_limits_or_references(tmp_path, selected): package, events = fixture(tmp_path) out = tmp_path / 'html' model = cli.generate(package, out, outputs=['html'], diagrams=selected) html = (out / 'narrative.html').read_text(encoding='utf-8') assert html.count(' assert text('heading.limits') in html and text('limit.review') in html ^^^^^^^^^^^^^^^^^^^^ tools/test_narrative_config.py:111: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = key = 'limit.review', params = {} def __call__(self, key, **params): > nodes = parse(self.values[key]) ^^^^^^^^^^^^^^^^ E KeyError: 'limit.review' tgwitness/narrative/text.py:138: KeyError _ test_optional_diagrams_cannot_hide_assurance_limits_or_references[selected2] _ tmp_path = PosixPath('/tmp/pytest-of-root/pytest-5/test_optional_diagrams_cannot_2') selected = ['ladder', 'files'] @pytest.mark.parametrize('selected', [[], ['timeline'], ['ladder', 'files']]) def test_optional_diagrams_cannot_hide_assurance_limits_or_references(tmp_path, selected): package, events = fixture(tmp_path) out = tmp_path / 'html' model = cli.generate(package, out, outputs=['html'], diagrams=selected) html = (out / 'narrative.html').read_text(encoding='utf-8') > assert html.count('(' = ' raise ValueError("Connect this account to Telegram first.") E ValueError: Connect this account to Telegram first. tgwitness/secret_chats.py:294: ValueError ____________________ test_independent_login_browser[False] _____________________ workspace = tmp_path = PosixPath('/tmp/pytest-of-root/pytest-5/test_independent_login_browser0') password = False @pytest.mark.parametrize("password", [False, True]) def test_independent_login_browser(workspace, tmp_path, password): from playwright.sync_api import expect, sync_playwright from tools.check_browser import RunningApp, unlock, navigate_panel from tools.browser_helpers import launch_browser, check_layout DonorClient.password = password raw = json.dumps({"session_str": DONOR, "api_id": 4, "api_hash": "a" * 32, "id": 44, **PROFILE, **({"twoFA": "wrong"} if password else {})}).encode() with RunningApp(tmp_path / "panel", client_factory=DonorClient) as server, sync_playwright() as p: browser = launch_browser(p) try: page = browser.new_page(viewport={"width": 1280, "height": 900}) errors = [] page.on("pageerror", lambda error: errors.append(str(error))) unlock(page, server) > navigate_panel(page, "connection") tools/test_session_import.py:339: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ tools/check_browser.py:157: in navigate_panel page.locator('.other-sign-in').evaluate('el=>el.open=true') ../../venv-dba742dbad616c88/lib/python3.12/site-packages/playwright/sync_api/_generated.py:11491: in evaluate self._sync( ../../venv-dba742dbad616c88/lib/python3.12/site-packages/playwright/_impl/_locator.py:204: in evaluate return await self._with_element( ../../venv-dba742dbad616c88/lib/python3.12/site-packages/playwright/_impl/_locator.py:123: in _with_element handle = await self.element_handle(timeout=timeout) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ../../venv-dba742dbad616c88/lib/python3.12/site-packages/playwright/_impl/_locator.py:334: in element_handle handle = await self._frame.wait_for_selector( ../../venv-dba742dbad616c88/lib/python3.12/site-packages/playwright/_impl/_frame.py:395: in wait_for_selector await self._channel.send( ../../venv-dba742dbad616c88/lib/python3.12/site-packages/playwright/_impl/_connection.py:78: in send return await self._connection.wrap_api_call( _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = cb = . at 0x7dd24576b600> is_internal = False, title = None async def wrap_api_call( self, cb: Callable[[], Any], is_internal: bool = False, title: str = None ) -> Any: if self._api_zone.get(): return await cb() task = asyncio.current_task(self._loop) parsed_st = _attach_api_call_information( getattr(task, "__pw_stack__", None) or _capture_stack_trace(), is_internal, title, ) self._api_zone.set(parsed_st) try: return await cb() except Exception as error: > raise rewrite_error(error, f"{parsed_st['apiName']}: {error}") from None E playwright._impl._errors.TimeoutError: Locator.evaluate: Timeout 30000ms exceeded. E Call log: E - waiting for locator(".other-sign-in") ../../venv-dba742dbad616c88/lib/python3.12/site-packages/playwright/_impl/_connection.py:636: TimeoutError ------------------------------ Captured log call ------------------------------- INFO tgwitness.journal:access.py:770 Main workspace · #1 process.started INFO mcp.server.streamable_http_manager:streamable_http_manager.py:162 StreamableHTTP session manager started INFO tgwitness.journal:access.py:770 Main workspace · #2 access.session_started INFO tgwitness.access:access.py:592 Session 0b6b998aba20c226 started for Main administrator from 127.0.0.1 INFO mcp.server.streamable_http_manager:streamable_http_manager.py:166 StreamableHTTP session manager shutting down INFO tgwitness.journal:access.py:770 Main workspace · #3 process.stopped · reason graceful shutdown _____________________ test_independent_login_browser[True] _____________________ workspace = tmp_path = PosixPath('/tmp/pytest-of-root/pytest-5/test_independent_login_browser1') password = True @pytest.mark.parametrize("password", [False, True]) def test_independent_login_browser(workspace, tmp_path, password): from playwright.sync_api import expect, sync_playwright from tools.check_browser import RunningApp, unlock, navigate_panel from tools.browser_helpers import launch_browser, check_layout DonorClient.password = password raw = json.dumps({"session_str": DONOR, "api_id": 4, "api_hash": "a" * 32, "id": 44, **PROFILE, **({"twoFA": "wrong"} if password else {})}).encode() with RunningApp(tmp_path / "panel", client_factory=DonorClient) as server, sync_playwright() as p: browser = launch_browser(p) try: page = browser.new_page(viewport={"width": 1280, "height": 900}) errors = [] page.on("pageerror", lambda error: errors.append(str(error))) unlock(page, server) > navigate_panel(page, "connection") tools/test_session_import.py:339: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ tools/check_browser.py:157: in navigate_panel page.locator('.other-sign-in').evaluate('el=>el.open=true') ../../venv-dba742dbad616c88/lib/python3.12/site-packages/playwright/sync_api/_generated.py:11491: in evaluate self._sync( ../../venv-dba742dbad616c88/lib/python3.12/site-packages/playwright/_impl/_locator.py:204: in evaluate return await self._with_element( ../../venv-dba742dbad616c88/lib/python3.12/site-packages/playwright/_impl/_locator.py:123: in _with_element handle = await self.element_handle(timeout=timeout) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ../../venv-dba742dbad616c88/lib/python3.12/site-packages/playwright/_impl/_locator.py:334: in element_handle handle = await self._frame.wait_for_selector( ../../venv-dba742dbad616c88/lib/python3.12/site-packages/playwright/_impl/_frame.py:395: in wait_for_selector await self._channel.send( ../../venv-dba742dbad616c88/lib/python3.12/site-packages/playwright/_impl/_connection.py:78: in send return await self._connection.wrap_api_call( _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = cb = . at 0x7dd2474322a0> is_internal = False, title = None async def wrap_api_call( self, cb: Callable[[], Any], is_internal: bool = False, title: str = None ) -> Any: if self._api_zone.get(): return await cb() task = asyncio.current_task(self._loop) parsed_st = _attach_api_call_information( getattr(task, "__pw_stack__", None) or _capture_stack_trace(), is_internal, title, ) self._api_zone.set(parsed_st) try: return await cb() except Exception as error: > raise rewrite_error(error, f"{parsed_st['apiName']}: {error}") from None E playwright._impl._errors.TimeoutError: Locator.evaluate: Timeout 30000ms exceeded. E Call log: E - waiting for locator(".other-sign-in") ../../venv-dba742dbad616c88/lib/python3.12/site-packages/playwright/_impl/_connection.py:636: TimeoutError ------------------------------ Captured log call ------------------------------- INFO tgwitness.journal:access.py:770 Main workspace · #1 process.started INFO mcp.server.streamable_http_manager:streamable_http_manager.py:162 StreamableHTTP session manager started INFO tgwitness.journal:access.py:770 Main workspace · #2 access.session_started INFO tgwitness.access:access.py:592 Session 50052c1871c79ec5 started for Main administrator from 127.0.0.1 INFO mcp.server.streamable_http_manager:streamable_http_manager.py:166 StreamableHTTP session manager shutting down INFO tgwitness.journal:access.py:770 Main workspace · #3 process.stopped · reason graceful shutdown ______ test_ots_structure_only_does_not_get_a_positive_indicator[unknown] ______ status = 'unknown' @pytest.mark.parametrize('status', ['pending', 'bitcoin-unverified', 'unknown']) def test_ots_structure_only_does_not_get_a_positive_indicator(status): console = verify.Console(io.StringIO(), 'en', False) checks = [] console.check = lambda state, label, detail: checks.append((state, label, detail)) console.timestamps([{'kind': 'opentimestamps', 'checkpoint': 'synthetic', 'service': 'test', 'status': status}]) assert checks[0][0] != 'ok' assert 'in Bitcoin:' not in checks[0][2] if status == 'unknown': > assert 'unknown' in checks[0][2] E AssertionError: assert 'unknown' in 'synthetic' tools/test_verifier_comparison.py:106: AssertionError _ test_direct_check_preserves_policy_and_archive_without_printing[tgwitness.verify] _ module = 'tgwitness.verify' capsys = <_pytest.capture.CaptureFixture object at 0x7dd224b1ccb0> @pytest.mark.parametrize('module', ['tgwitness.verify', 'tgwitness.verifier.cli']) def test_direct_check_preserves_policy_and_archive_without_printing(module, capsys): reader = importlib.import_module(module) expected = json.loads(EXPECTED.read_bytes()) policy = reader.verification_parser().parse_args(['--fingerprint', expected['result']['fingerprint']]) unchanged = copy.deepcopy(vars(policy)) archive_hash = hashlib.sha256(FIXTURE.read_bytes()).hexdigest() result = reader.verify_input(FIXTURE, policy) assert result.kind == 'evidence' and result.signer_pinned > assert same_decisions(result.details, expected['result']) E AssertionError: assert False E + where False = same_decisions({'events': 4, 'head_hash': 'b5b759fc6898cac1baa7f5da4567510a1318060e0b756a6357dbcff27bf5cdd2', 'fingerprint': '56475aa...08c', 'coverage': {'continuous': [], 'gaps': [], 'session_windows': [], 'record_sources': {'unlabelled': 3}, ...}, ...}, {'events': 4, 'head_hash': 'b5b759fc6898cac1baa7f5da4567510a1318060e0b756a6357dbcff27bf5cdd2', 'fingerprint': '56475aa...3da651358839e9b77481b2eab107708c', 'coverage': {'continuous': [], 'gaps': [], 'notes': [], 'notes_total': 0, ...}, ...}) E + where {'events': 4, 'head_hash': 'b5b759fc6898cac1baa7f5da4567510a1318060e0b756a6357dbcff27bf5cdd2', 'fingerprint': '56475aa...08c', 'coverage': {'continuous': [], 'gaps': [], 'session_windows': [], 'record_sources': {'unlabelled': 3}, ...}, ...} = .details tools/test_verifier_dispatch.py:24: AssertionError _ test_direct_check_preserves_policy_and_archive_without_printing[tgwitness.verifier.cli] _ module = 'tgwitness.verifier.cli' capsys = <_pytest.capture.CaptureFixture object at 0x7dd224b1df10> @pytest.mark.parametrize('module', ['tgwitness.verify', 'tgwitness.verifier.cli']) def test_direct_check_preserves_policy_and_archive_without_printing(module, capsys): reader = importlib.import_module(module) expected = json.loads(EXPECTED.read_bytes()) policy = reader.verification_parser().parse_args(['--fingerprint', expected['result']['fingerprint']]) unchanged = copy.deepcopy(vars(policy)) archive_hash = hashlib.sha256(FIXTURE.read_bytes()).hexdigest() result = reader.verify_input(FIXTURE, policy) assert result.kind == 'evidence' and result.signer_pinned > assert same_decisions(result.details, expected['result']) E AssertionError: assert False E + where False = same_decisions({'events': 4, 'head_hash': 'b5b759fc6898cac1baa7f5da4567510a1318060e0b756a6357dbcff27bf5cdd2', 'fingerprint': '56475aa...08c', 'coverage': {'continuous': [], 'gaps': [], 'session_windows': [], 'record_sources': {'unlabelled': 3}, ...}, ...}, {'events': 4, 'head_hash': 'b5b759fc6898cac1baa7f5da4567510a1318060e0b756a6357dbcff27bf5cdd2', 'fingerprint': '56475aa...3da651358839e9b77481b2eab107708c', 'coverage': {'continuous': [], 'gaps': [], 'notes': [], 'notes_total': 0, ...}, ...}) E + where {'events': 4, 'head_hash': 'b5b759fc6898cac1baa7f5da4567510a1318060e0b756a6357dbcff27bf5cdd2', 'fingerprint': '56475aa...08c', 'coverage': {'continuous': [], 'gaps': [], 'session_windows': [], 'record_sources': {'unlabelled': 3}, ...}, ...} = .details tools/test_verifier_dispatch.py:24: AssertionError _____________ test_review_modules_import_without_application_state _____________ def test_review_modules_import_without_application_state(): for part in PARTS: importlib.import_module('tgwitness.verifier.' + part) from tgwitness.verifier.bundles import verify_bundle expected = json.loads(EXPECTED.read_bytes()) > assert same_decisions(verify_bundle(FIXTURE, expected['result']['fingerprint']), expected['result']) E AssertionError: assert False E + where False = same_decisions({'events': 4, 'head_hash': 'b5b759fc6898cac1baa7f5da4567510a1318060e0b756a6357dbcff27bf5cdd2', 'fingerprint': '56475aa...08c', 'coverage': {'continuous': [], 'gaps': [], 'session_windows': [], 'record_sources': {'unlabelled': 3}, ...}, ...}, {'events': 4, 'head_hash': 'b5b759fc6898cac1baa7f5da4567510a1318060e0b756a6357dbcff27bf5cdd2', 'fingerprint': '56475aa...3da651358839e9b77481b2eab107708c', 'coverage': {'continuous': [], 'gaps': [], 'notes': [], 'notes_total': 0, ...}, ...}) E + where {'events': 4, 'head_hash': 'b5b759fc6898cac1baa7f5da4567510a1318060e0b756a6357dbcff27bf5cdd2', 'fingerprint': '56475aa...08c', 'coverage': {'continuous': [], 'gaps': [], 'session_windows': [], 'record_sources': {'unlabelled': 3}, ...}, ...} = (PosixPath('/workspace/qa/src/23c7cc65e776bca40b989ff73d9d2a438954604e/tools/fixtures/evidence-before-refactor.zip'), '56475aa75463474c0285df5dbf2bcab73da651358839e9b77481b2eab107708c') tools/test_verifier_sources.py:113: AssertionError _______________ test_frozen_verification_decisions_are_unchanged _______________ def test_frozen_verification_decisions_are_unchanged(): expected = EXPECTED.read_bytes() pin = json.loads(expected)['result']['fingerprint'] result = execute(OUTPUT, FIXTURE, '--json', '--fingerprint', pin) assert result.returncode == 0, result.stderr > assert same_decisions(result.stdout, expected) E assert False E + where False = same_decisions(b'{\n "verified": true,\n "kind": "evidence",\n "signer_pinned": true,\n "notes": [\n "Message records by sourc... },\n "requested_checks_unavailable": []\n },\n "evidence_profile": "integrity",\n "requirements_met": true\n}\n', b'{\n "verified": true,\n "kind": "evidence",\n "signer_pinned": true,\n "notes": [\n "Chat -1001000000001: IDs... exported head; no claim of continuous or complete Telegram observation"\n }\n },\n "requirements_met": true\n}\n') E + where b'{\n "verified": true,\n "kind": "evidence",\n "signer_pinned": true,\n "notes": [\n "Message records by sourc... },\n "requested_checks_unavailable": []\n },\n "evidence_profile": "integrity",\n "requirements_met": true\n}\n' = CompletedProcess(args=['/workspace/qa/venv-dba742dbad616c88/bin/python', '-I', '/workspace/qa/src/23c7cc65e776bca40b98...uested_checks_unavailable": []\n },\n "evidence_profile": "integrity",\n "requirements_met": true\n}\n', stderr=b'').stdout tools/test_verifier_sources.py:121: AssertionError _________ test_old_and_new_decisions_and_statuses_match[pinned---json] _________ previous = PosixPath('/tmp/pytest-of-root/pytest-5/test_old_and_new_decisions_and0/previous.py') mode = '--json', policy = 'pinned' @pytest.mark.parametrize('mode', ['--json', '--plain', '--pretty']) @pytest.mark.parametrize('policy', ['pinned', 'unpinned', 'wrong_key', 'unmet_tier']) def test_old_and_new_decisions_and_statuses_match(previous, mode, policy): pin = json.loads(EXPECTED.read_bytes())['result']['fingerprint'] options = [mode, '--no-color', '--lang', 'en', '--strict'] if policy != 'unpinned': options += ['--fingerprint', '0' * 64 if policy == 'wrong_key' else pin] if policy == 'unmet_tier': options += ['--require-tier', 'witnessed'] before, after = (execute(script, FIXTURE, *options) for script in (previous, OUTPUT)) assert after.returncode == before.returncode assert after.stderr == before.stderr if mode == '--json': > assert same_decisions(after.stdout, before.stdout) E assert False E + where False = same_decisions(b'{\n "verified": true,\n "kind": "evidence",\n "signer_pinned": true,\n "notes": [\n "Message records by sourc... },\n "requested_checks_unavailable": []\n },\n "evidence_profile": "integrity",\n "requirements_met": true\n}\n', b'{\n "verified": true,\n "kind": "evidence",\n "signer_pinned": true,\n "notes": [\n "Chat -1001000000001: IDs... exported head; no claim of continuous or complete Telegram observation"\n }\n },\n "requirements_met": true\n}\n') E + where b'{\n "verified": true,\n "kind": "evidence",\n "signer_pinned": true,\n "notes": [\n "Message records by sourc... },\n "requested_checks_unavailable": []\n },\n "evidence_profile": "integrity",\n "requirements_met": true\n}\n' = CompletedProcess(args=['/workspace/qa/venv-dba742dbad616c88/bin/python', '-I', '/workspace/qa/src/23c7cc65e776bca40b98...uested_checks_unavailable": []\n },\n "evidence_profile": "integrity",\n "requirements_met": true\n}\n', stderr=b'').stdout E + and b'{\n "verified": true,\n "kind": "evidence",\n "signer_pinned": true,\n "notes": [\n "Chat -1001000000001: IDs... exported head; no claim of continuous or complete Telegram observation"\n }\n },\n "requirements_met": true\n}\n' = CompletedProcess(args=['/workspace/qa/venv-dba742dbad616c88/bin/python', '-I', '/tmp/pytest-of-root/pytest-5/test_old_...d; no claim of continuous or complete Telegram observation"\n }\n },\n "requirements_met": true\n}\n', stderr=b'').stdout tools/test_verifier_sources.py:137: AssertionError ________ test_old_and_new_decisions_and_statuses_match[pinned---plain] _________ previous = PosixPath('/tmp/pytest-of-root/pytest-5/test_old_and_new_decisions_and1/previous.py') mode = '--plain', policy = 'pinned' @pytest.mark.parametrize('mode', ['--json', '--plain', '--pretty']) @pytest.mark.parametrize('policy', ['pinned', 'unpinned', 'wrong_key', 'unmet_tier']) def test_old_and_new_decisions_and_statuses_match(previous, mode, policy): pin = json.loads(EXPECTED.read_bytes())['result']['fingerprint'] options = [mode, '--no-color', '--lang', 'en', '--strict'] if policy != 'unpinned': options += ['--fingerprint', '0' * 64 if policy == 'wrong_key' else pin] if policy == 'unmet_tier': options += ['--require-tier', 'witnessed'] before, after = (execute(script, FIXTURE, *options) for script in (previous, OUTPUT)) assert after.returncode == before.returncode assert after.stderr == before.stderr if mode == '--json': assert same_decisions(after.stdout, before.stdout) elif mode == '--plain' and plain_result(before.stdout) is not None: > assert same_decisions(plain_result(after.stdout), plain_result(before.stdout)) E assert False E + where False = same_decisions({'events': 4, 'head_hash': 'b5b759fc6898cac1baa7f5da4567510a1318060e0b756a6357dbcff27bf5cdd2', 'fingerprint': '56475aa...08c', 'coverage': {'continuous': [], 'gaps': [], 'session_windows': [], 'record_sources': {'unlabelled': 3}, ...}, ...}, {'events': 4, 'head_hash': 'b5b759fc6898cac1baa7f5da4567510a1318060e0b756a6357dbcff27bf5cdd2', 'fingerprint': '56475aa...3da651358839e9b77481b2eab107708c', 'coverage': {'continuous': [], 'gaps': [], 'notes': [], 'notes_total': 0, ...}, ...}) E + where {'events': 4, 'head_hash': 'b5b759fc6898cac1baa7f5da4567510a1318060e0b756a6357dbcff27bf5cdd2', 'fingerprint': '56475aa...08c', 'coverage': {'continuous': [], 'gaps': [], 'session_windows': [], 'record_sources': {'unlabelled': 3}, ...}, ...} = plain_result(b'EVIDENCE: minimum not met \xc2\xb7 missing: external time from a third party covering the last record\n [met] Integ...d.\nIntegrity verified. Minimum not met \xc2\xb7 missing: external time from a third party covering the last record.\n') E + where b'EVIDENCE: minimum not met \xc2\xb7 missing: external time from a third party covering the last record\n [met] Integ...d.\nIntegrity verified. Minimum not met \xc2\xb7 missing: external time from a third party covering the last record.\n' = CompletedProcess(args=['/workspace/qa/venv-dba742dbad616c88/bin/python', '-I', '/workspace/qa/src/23c7cc65e776bca40b98... verified. Minimum not met \xc2\xb7 missing: external time from a third party covering the last record.\n', stderr=b'').stdout E + and {'events': 4, 'head_hash': 'b5b759fc6898cac1baa7f5da4567510a1318060e0b756a6357dbcff27bf5cdd2', 'fingerprint': '56475aa...3da651358839e9b77481b2eab107708c', 'coverage': {'continuous': [], 'gaps': [], 'notes': [], 'notes_total': 0, ...}, ...} = plain_result(b'ASSURANCE: self_attested \xe2\x80\x94 only the collector\'s own key vouches for this record\n{\n "events": 4,\n "h...point kept away from the collector.\nIntegrity verified. Source authenticity and clock accuracy are not established.\n') E + where b'ASSURANCE: self_attested \xe2\x80\x94 only the collector\'s own key vouches for this record\n{\n "events": 4,\n "h...point kept away from the collector.\nIntegrity verified. Source authenticity and clock accuracy are not established.\n' = CompletedProcess(args=['/workspace/qa/venv-dba742dbad616c88/bin/python', '-I', '/tmp/pytest-of-root/pytest-5/test_old_...ay from the collector.\nIntegrity verified. Source authenticity and clock accuracy are not established.\n', stderr=b'').stdout tools/test_verifier_sources.py:139: AssertionError ________ test_old_and_new_decisions_and_statuses_match[unpinned---json] ________ previous = PosixPath('/tmp/pytest-of-root/pytest-5/test_old_and_new_decisions_and3/previous.py') mode = '--json', policy = 'unpinned' @pytest.mark.parametrize('mode', ['--json', '--plain', '--pretty']) @pytest.mark.parametrize('policy', ['pinned', 'unpinned', 'wrong_key', 'unmet_tier']) def test_old_and_new_decisions_and_statuses_match(previous, mode, policy): pin = json.loads(EXPECTED.read_bytes())['result']['fingerprint'] options = [mode, '--no-color', '--lang', 'en', '--strict'] if policy != 'unpinned': options += ['--fingerprint', '0' * 64 if policy == 'wrong_key' else pin] if policy == 'unmet_tier': options += ['--require-tier', 'witnessed'] before, after = (execute(script, FIXTURE, *options) for script in (previous, OUTPUT)) assert after.returncode == before.returncode assert after.stderr == before.stderr if mode == '--json': > assert same_decisions(after.stdout, before.stdout) E assert False E + where False = same_decisions(b'{\n "verified": true,\n "kind": "evidence",\n "signer_pinned": false,\n "notes": [\n "Message records by sour...},\n "requested_checks_unavailable": []\n },\n "evidence_profile": "integrity",\n "requirements_met": false\n}\n', b'{\n "verified": true,\n "kind": "evidence",\n "signer_pinned": false,\n "notes": [\n "Chat -1001000000001: ID...exported head; no claim of continuous or complete Telegram observation"\n }\n },\n "requirements_met": false\n}\n') E + where b'{\n "verified": true,\n "kind": "evidence",\n "signer_pinned": false,\n "notes": [\n "Message records by sour...},\n "requested_checks_unavailable": []\n },\n "evidence_profile": "integrity",\n "requirements_met": false\n}\n' = CompletedProcess(args=['/workspace/qa/venv-dba742dbad616c88/bin/python', '-I', '/workspace/qa/src/23c7cc65e776bca40b98...ested_checks_unavailable": []\n },\n "evidence_profile": "integrity",\n "requirements_met": false\n}\n', stderr=b'').stdout E + and b'{\n "verified": true,\n "kind": "evidence",\n "signer_pinned": false,\n "notes": [\n "Chat -1001000000001: ID...exported head; no claim of continuous or complete Telegram observation"\n }\n },\n "requirements_met": false\n}\n' = CompletedProcess(args=['/workspace/qa/venv-dba742dbad616c88/bin/python', '-I', '/tmp/pytest-of-root/pytest-5/test_old_...; no claim of continuous or complete Telegram observation"\n }\n },\n "requirements_met": false\n}\n', stderr=b'').stdout tools/test_verifier_sources.py:137: AssertionError _______ test_old_and_new_decisions_and_statuses_match[unpinned---plain] ________ previous = PosixPath('/tmp/pytest-of-root/pytest-5/test_old_and_new_decisions_and4/previous.py') mode = '--plain', policy = 'unpinned' @pytest.mark.parametrize('mode', ['--json', '--plain', '--pretty']) @pytest.mark.parametrize('policy', ['pinned', 'unpinned', 'wrong_key', 'unmet_tier']) def test_old_and_new_decisions_and_statuses_match(previous, mode, policy): pin = json.loads(EXPECTED.read_bytes())['result']['fingerprint'] options = [mode, '--no-color', '--lang', 'en', '--strict'] if policy != 'unpinned': options += ['--fingerprint', '0' * 64 if policy == 'wrong_key' else pin] if policy == 'unmet_tier': options += ['--require-tier', 'witnessed'] before, after = (execute(script, FIXTURE, *options) for script in (previous, OUTPUT)) assert after.returncode == before.returncode assert after.stderr == before.stderr if mode == '--json': assert same_decisions(after.stdout, before.stdout) elif mode == '--plain' and plain_result(before.stdout) is not None: > assert same_decisions(plain_result(after.stdout), plain_result(before.stdout)) E assert False E + where False = same_decisions({'events': 4, 'head_hash': 'b5b759fc6898cac1baa7f5da4567510a1318060e0b756a6357dbcff27bf5cdd2', 'fingerprint': '56475aa...08c', 'coverage': {'continuous': [], 'gaps': [], 'session_windows': [], 'record_sources': {'unlabelled': 3}, ...}, ...}, {'events': 4, 'head_hash': 'b5b759fc6898cac1baa7f5da4567510a1318060e0b756a6357dbcff27bf5cdd2', 'fingerprint': '56475aa...3da651358839e9b77481b2eab107708c', 'coverage': {'continuous': [], 'gaps': [], 'notes': [], 'notes_total': 0, ...}, ...}) E + where {'events': 4, 'head_hash': 'b5b759fc6898cac1baa7f5da4567510a1318060e0b756a6357dbcff27bf5cdd2', 'fingerprint': '56475aa...08c', 'coverage': {'continuous': [], 'gaps': [], 'session_windows': [], 'record_sources': {'unlabelled': 3}, ...}, ...} = plain_result(b'EVIDENCE: minimum not met \xc2\xb7 missing: confirmed signer key; external time from a third party covering the last.... Minimum not met \xc2\xb7 missing: confirmed signer key; external time from a third party covering the last record.\n') E + where b'EVIDENCE: minimum not met \xc2\xb7 missing: confirmed signer key; external time from a third party covering the last.... Minimum not met \xc2\xb7 missing: confirmed signer key; external time from a third party covering the last record.\n' = CompletedProcess(args=['/workspace/qa/venv-dba742dbad616c88/bin/python', '-I', '/workspace/qa/src/23c7cc65e776bca40b98... met \xc2\xb7 missing: confirmed signer key; external time from a third party covering the last record.\n', stderr=b'').stdout E + and {'events': 4, 'head_hash': 'b5b759fc6898cac1baa7f5da4567510a1318060e0b756a6357dbcff27bf5cdd2', 'fingerprint': '56475aa...3da651358839e9b77481b2eab107708c', 'coverage': {'continuous': [], 'gaps': [], 'notes': [], 'notes_total': 0, ...}, ...} = plain_result(b'ASSURANCE: self_attested \xe2\x80\x94 only the collector\'s own key vouches for this record\n{\n "events": 4,\n "h... clock accuracy are not established.\nSigner identity is unpinned: retain and compare the fingerprint independently.\n') E + where b'ASSURANCE: self_attested \xe2\x80\x94 only the collector\'s own key vouches for this record\n{\n "events": 4,\n "h... clock accuracy are not established.\nSigner identity is unpinned: retain and compare the fingerprint independently.\n' = CompletedProcess(args=['/workspace/qa/venv-dba742dbad616c88/bin/python', '-I', '/tmp/pytest-of-root/pytest-5/test_old_...cy are not established.\nSigner identity is unpinned: retain and compare the fingerprint independently.\n', stderr=b'').stdout tools/test_verifier_sources.py:139: AssertionError _______ test_old_and_new_decisions_and_statuses_match[unmet_tier---json] _______ previous = PosixPath('/tmp/pytest-of-root/pytest-5/test_old_and_new_decisions_and9/previous.py') mode = '--json', policy = 'unmet_tier' @pytest.mark.parametrize('mode', ['--json', '--plain', '--pretty']) @pytest.mark.parametrize('policy', ['pinned', 'unpinned', 'wrong_key', 'unmet_tier']) def test_old_and_new_decisions_and_statuses_match(previous, mode, policy): pin = json.loads(EXPECTED.read_bytes())['result']['fingerprint'] options = [mode, '--no-color', '--lang', 'en', '--strict'] if policy != 'unpinned': options += ['--fingerprint', '0' * 64 if policy == 'wrong_key' else pin] if policy == 'unmet_tier': options += ['--require-tier', 'witnessed'] before, after = (execute(script, FIXTURE, *options) for script in (previous, OUTPUT)) assert after.returncode == before.returncode assert after.stderr == before.stderr if mode == '--json': > assert same_decisions(after.stdout, before.stdout) E assert False E + where False = same_decisions(b'{\n "verified": true,\n "kind": "evidence",\n "signer_pinned": true,\n "notes": [\n "Message records by sourc...},\n "requested_checks_unavailable": []\n },\n "evidence_profile": "integrity",\n "requirements_met": false\n}\n', b'{\n "verified": true,\n "kind": "evidence",\n "signer_pinned": true,\n "notes": [\n "Chat -1001000000001: IDs...exported head; no claim of continuous or complete Telegram observation"\n }\n },\n "requirements_met": false\n}\n') E + where b'{\n "verified": true,\n "kind": "evidence",\n "signer_pinned": true,\n "notes": [\n "Message records by sourc...},\n "requested_checks_unavailable": []\n },\n "evidence_profile": "integrity",\n "requirements_met": false\n}\n' = CompletedProcess(args=['/workspace/qa/venv-dba742dbad616c88/bin/python', '-I', '/workspace/qa/src/23c7cc65e776bca40b98...ested_checks_unavailable": []\n },\n "evidence_profile": "integrity",\n "requirements_met": false\n}\n', stderr=b'').stdout E + and b'{\n "verified": true,\n "kind": "evidence",\n "signer_pinned": true,\n "notes": [\n "Chat -1001000000001: IDs...exported head; no claim of continuous or complete Telegram observation"\n }\n },\n "requirements_met": false\n}\n' = CompletedProcess(args=['/workspace/qa/venv-dba742dbad616c88/bin/python', '-I', '/tmp/pytest-of-root/pytest-5/test_old_...; no claim of continuous or complete Telegram observation"\n }\n },\n "requirements_met": false\n}\n', stderr=b'').stdout tools/test_verifier_sources.py:137: AssertionError ______ test_old_and_new_decisions_and_statuses_match[unmet_tier---plain] _______ previous = PosixPath('/tmp/pytest-of-root/pytest-5/test_old_and_new_decisions_and10/previous.py') mode = '--plain', policy = 'unmet_tier' @pytest.mark.parametrize('mode', ['--json', '--plain', '--pretty']) @pytest.mark.parametrize('policy', ['pinned', 'unpinned', 'wrong_key', 'unmet_tier']) def test_old_and_new_decisions_and_statuses_match(previous, mode, policy): pin = json.loads(EXPECTED.read_bytes())['result']['fingerprint'] options = [mode, '--no-color', '--lang', 'en', '--strict'] if policy != 'unpinned': options += ['--fingerprint', '0' * 64 if policy == 'wrong_key' else pin] if policy == 'unmet_tier': options += ['--require-tier', 'witnessed'] before, after = (execute(script, FIXTURE, *options) for script in (previous, OUTPUT)) assert after.returncode == before.returncode assert after.stderr == before.stderr if mode == '--json': assert same_decisions(after.stdout, before.stdout) elif mode == '--plain' and plain_result(before.stdout) is not None: > assert same_decisions(plain_result(after.stdout), plain_result(before.stdout)) E assert False E + where False = same_decisions({'events': 4, 'head_hash': 'b5b759fc6898cac1baa7f5da4567510a1318060e0b756a6357dbcff27bf5cdd2', 'fingerprint': '56475aa...08c', 'coverage': {'continuous': [], 'gaps': [], 'session_windows': [], 'record_sources': {'unlabelled': 3}, ...}, ...}, {'events': 4, 'head_hash': 'b5b759fc6898cac1baa7f5da4567510a1318060e0b756a6357dbcff27bf5cdd2', 'fingerprint': '56475aa...3da651358839e9b77481b2eab107708c', 'coverage': {'continuous': [], 'gaps': [], 'notes': [], 'notes_total': 0, ...}, ...}) E + where {'events': 4, 'head_hash': 'b5b759fc6898cac1baa7f5da4567510a1318060e0b756a6357dbcff27bf5cdd2', 'fingerprint': '56475aa...08c', 'coverage': {'continuous': [], 'gaps': [], 'session_windows': [], 'record_sources': {'unlabelled': 3}, ...}, ...} = plain_result(b'EVIDENCE: minimum not met \xc2\xb7 missing: external time from a third party covering the last record\n [met] Integ...ed\nIntegrity verified. Minimum not met \xc2\xb7 missing: external time from a third party covering the last record.\n') E + where b'EVIDENCE: minimum not met \xc2\xb7 missing: external time from a third party covering the last record\n [met] Integ...ed\nIntegrity verified. Minimum not met \xc2\xb7 missing: external time from a third party covering the last record.\n' = CompletedProcess(args=['/workspace/qa/venv-dba742dbad616c88/bin/python', '-I', '/workspace/qa/src/23c7cc65e776bca40b98... verified. Minimum not met \xc2\xb7 missing: external time from a third party covering the last record.\n', stderr=b'').stdout E + and {'events': 4, 'head_hash': 'b5b759fc6898cac1baa7f5da4567510a1318060e0b756a6357dbcff27bf5cdd2', 'fingerprint': '56475aa...3da651358839e9b77481b2eab107708c', 'coverage': {'continuous': [], 'gaps': [], 'notes': [], 'notes_total': 0, ...}, ...} = plain_result(b'ASSURANCE: self_attested \xe2\x80\x94 only the collector\'s own key vouches for this record\n{\n "events": 4,\n "h...nce tier was not reached: witnessed\nIntegrity verified. Source authenticity and clock accuracy are not established.\n') E + where b'ASSURANCE: self_attested \xe2\x80\x94 only the collector\'s own key vouches for this record\n{\n "events": 4,\n "h...nce tier was not reached: witnessed\nIntegrity verified. Source authenticity and clock accuracy are not established.\n' = CompletedProcess(args=['/workspace/qa/venv-dba742dbad616c88/bin/python', '-I', '/tmp/pytest-of-root/pytest-5/test_old_...not reached: witnessed\nIntegrity verified. Source authenticity and clock accuracy are not established.\n', stderr=b'').stdout tools/test_verifier_sources.py:139: AssertionError ______ test_old_verifier_accepts_new_archive_with_identical_signed_events ______ previous = PosixPath('/tmp/pytest-of-root/pytest-5/test_old_verifier_accepts_new_0/previous.py') tmp_path = PosixPath('/tmp/pytest-of-root/pytest-5/test_old_verifier_accepts_new_0') def test_old_verifier_accepts_new_archive_with_identical_signed_events(previous, tmp_path): root = tmp_path / 'journal' root.mkdir() signer, store = SyntheticSigner(), Store(root) try: store.bind(signer) with zipfile.ZipFile(FIXTURE) as archive: signed = archive.read('events.jsonl') for line in signed.splitlines(): event = json.loads(line) with patch('tgwitness.store.utcnow', return_value=event['observed_at']): store.append(**{key:event[key] for key in ('kind','payload','chat_id','message_id','actor_id','source_at')}) current = evidence.export_file(store, signer, 'zip', compact=True, include_board=False) with zipfile.ZipFile(current) as archive: assert archive.read('events.jsonl') == signed assert archive.read('verify.py') == OUTPUT.read_bytes() pin = verify.fingerprint(signer.public_key) old_result, new_result = (execute(script, current, '--json', '--fingerprint', pin) for script in (previous, OUTPUT)) assert old_result.returncode == new_result.returncode == 0 > assert same_decisions(new_result.stdout, old_result.stdout) E assert False E + where False = same_decisions(b'{\n "verified": true,\n "kind": "evidence",\n "signer_pinned": true,\n "notes": [\n "Message records by sourc... },\n "requested_checks_unavailable": []\n },\n "evidence_profile": "integrity",\n "requirements_met": true\n}\n', b'{\n "verified": true,\n "kind": "evidence",\n "signer_pinned": true,\n "notes": [\n "Chat -1001000000001: IDs... exported head; no claim of continuous or complete Telegram observation"\n }\n },\n "requirements_met": true\n}\n') E + where b'{\n "verified": true,\n "kind": "evidence",\n "signer_pinned": true,\n "notes": [\n "Message records by sourc... },\n "requested_checks_unavailable": []\n },\n "evidence_profile": "integrity",\n "requirements_met": true\n}\n' = CompletedProcess(args=['/workspace/qa/venv-dba742dbad616c88/bin/python', '-I', '/workspace/qa/src/23c7cc65e776bca40b98...uested_checks_unavailable": []\n },\n "evidence_profile": "integrity",\n "requirements_met": true\n}\n', stderr=b'').stdout E + and b'{\n "verified": true,\n "kind": "evidence",\n "signer_pinned": true,\n "notes": [\n "Chat -1001000000001: IDs... exported head; no claim of continuous or complete Telegram observation"\n }\n },\n "requirements_met": true\n}\n' = CompletedProcess(args=['/workspace/qa/venv-dba742dbad616c88/bin/python', '-I', '/tmp/pytest-of-root/pytest-5/test_old_...d; no claim of continuous or complete Telegram observation"\n }\n },\n "requirements_met": true\n}\n', stderr=b'').stdout tools/test_verifier_sources.py:190: AssertionError ________ test_terms_patterns_wallets_usernames_and_domains_are_matched _________ store = def test_terms_patterns_wallets_usernames_and_domains_are_matched(store): with_entries(store, {"kind": "term", "value": "release fee"}, {"kind": "regex", "value": r"\b0\.\d+\s?BTC\b"}, {"kind": "wallet", "value": WALLET}, {"kind": "username", "value": "@Fictional_Admin"}, {"kind": "domain", "value": "pay-fictional.invalid"}, {"kind": "phone", "value": "+1 555 000 1234"}) record(store, "Send the release fee of 0.01 BTC to " + WALLET) record(store, "Write @fictional_admin at https://login.pay-fictional.invalid/x", message_id=2) record(store, "Call +15550001234 now", message_id=3) record(store, "nothing interesting here", message_id=4) result = watchlists.scan(store) found = watchlists.hits(store) assert result["hits"] == 6 and len(found) == 6 assert {item["kind"] for item in found} == {"term", "regex", "wallet", "username", "domain", "phone"} > assert all("nothing about who wrote it" in (store.events(kind="watchlist.hit")[0]["payload"]["meaning"]) for _ in [0]) E assert False E + where False = all(. at 0x7dd25f4365e0>) tools/test_watchlists.py:61: AssertionError ____ test_cloudflare_queries_are_read_only_scoped_and_token_is_not_exported ____ tmp_path = PosixPath('/tmp/pytest-of-root/pytest-5/test_cloudflare_queries_are_re0') def test_cloudflare_queries_are_read_only_scoped_and_token_is_not_exported(tmp_path): journal = Journal(tmp_path / "witness") token = "synthetic-provider-read-token" config = {"account": "a" * 32, "connector_id": "00000000-0000-0000-0000-000000000001", "gateway_location": "00000000-0000-0000-0000-000000000002", "source_ip": "192.0.2.5"} calls = [] def request(path, supplied, body=None): assert supplied == token calls.append((path, body)) if path == "/graphql": assert "mutation" not in body["query"] and body["variables"]["source"] == "192.0.2.5" return {"data": {"viewer": {"accounts": [{"cf1GatewayDnsRawGroups": []}]}}} return {"success": True, "result": {"status": "healthy"}} try: event = provider_observe(journal, config, token, request) assert len(calls) == 3 and all("/token" not in path for path, _ in calls) assert event["payload"]["outcomes"]["dns"]["complete"] is False > assert "no proof of continuous presence" in event["payload"]["scope"] E AssertionError: assert 'no proof of continuous presence' in 'provider state sampled at the polled time' addons/capture/tests/test_trusted_anchors.py:60: AssertionError =============================== warnings summary =============================== tools/test_client_checks.py::test_reported_connection_keeps_actual_language_pack /workspace/qa/src/23c7cc65e776bca40b989ff73d9d2a438954604e/tools/test_client_checks.py:110: UserWarning: Telethon's schema layer differs from the reviewed profile baseline (230); review library compatibility. Imported profile values are retained. fake = collector.make_client(6, "a" * 32) tools/test_session_import.py: 20 warnings /workspace/qa/src/23c7cc65e776bca40b989ff73d9d2a438954604e/tgwitness/session_import.py:113: UserWarning: Telethon's schema layer differs from the reviewed profile baseline (230); review library compatibility. Imported profile values are retained. donor = c.make_client(api_id, api_hash, session, supplied or None, languages) tools/test_session_import.py: 17 warnings /workspace/qa/src/23c7cc65e776bca40b989ff73d9d2a438954604e/tgwitness/session_import.py:74: UserWarning: Telethon's schema layer differs from the reviewed profile baseline (230); review library compatibility. Imported profile values are retained. candidate = c.make_client(credentials["api_id"], credentials["api_hash"], tools/test_session_import.py::test_independent_authorization_and_provenance /workspace/qa/src/23c7cc65e776bca40b989ff73d9d2a438954604e/tools/test_session_import.py:148: UserWarning: Telethon's schema layer differs from the reviewed profile baseline (230); review library compatibility. Imported profile values are retained. donor = c.make_client(4, "a" * 32, DONOR, PROFILE) tools/test_session_import.py: 11 warnings /workspace/qa/src/23c7cc65e776bca40b989ff73d9d2a438954604e/tgwitness/session_import.py:113: UserWarning: The mobile system_lang_code has no region component. Imported profile values are retained. donor = c.make_client(api_id, api_hash, session, supplied or None, languages) tools/test_session_import.py::test_invalid_donor_does_not_expire_saved_authorization /workspace/qa/src/23c7cc65e776bca40b989ff73d9d2a438954604e/tgwitness/collector.py:1779: UserWarning: Telethon's schema layer differs from the reviewed profile baseline (230); review library compatibility. Imported profile values are retained. candidate = self.make_client(api_id, api_hash, session, client_profile, languages) -- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html =========================== short test summary info ============================ FAILED tools/test_analyzer_graphs.py::test_edges_cite_journal_records_across_chosen_chats FAILED tools/test_analyzer_linking.py::test_rotated_account_ranks_first_with_explanation_and_citations FAILED tools/test_case_package.py::test_package_contains_readable_report_files_and_explanations[tsr] FAILED tools/test_case_package.py::test_package_contains_readable_report_files_and_explanations[ots] FAILED tools/test_chat_export_integrity.py::test_sparse_message_numbers_are_counted_without_expansion FAILED tools/test_cli.py::test_local_commands - AssertionError: assert [{'wor... FAILED tools/test_deletion_semantics.py::test_deletion_of_subset_keeps_actor_and_whole_history_unknown[2-55123] FAILED tools/test_deletion_semantics.py::test_deletion_of_subset_keeps_actor_and_whole_history_unknown[2--1000000000555] FAILED tools/test_deletion_semantics.py::test_deletion_of_subset_keeps_actor_and_whole_history_unknown[9-55123] FAILED tools/test_deletion_semantics.py::test_deletion_of_subset_keeps_actor_and_whole_history_unknown[9--1000000000555] FAILED tools/test_deletion_semantics.py::test_deletion_of_subset_keeps_actor_and_whole_history_unknown[10-55123] FAILED tools/test_deletion_semantics.py::test_deletion_of_subset_keeps_actor_and_whole_history_unknown[10--1000000000555] FAILED tools/test_deletion_semantics.py::test_deletion_of_subset_keeps_actor_and_whole_history_unknown[15-55123] FAILED tools/test_deletion_semantics.py::test_deletion_of_subset_keeps_actor_and_whole_history_unknown[15--1000000000555] FAILED tools/test_device_attribution.py::test_the_dossier_counts_clients_sticker_sets_and_prepared_media FAILED tools/test_jurisdiction_guidance.py::test_choices_do_not_upgrade_facts_or_claim_safeguards_were_used FAILED tools/test_mtproto_forensics.py::test_outbox_read_watermark_does_not_identify_a_person FAILED tools/test_narrative.py::test_pdf_html_and_svg_outputs[en] - KeyError:... FAILED tools/test_narrative.py::test_pdf_html_and_svg_outputs[de] - KeyError:... FAILED tools/test_narrative.py::test_pdf_html_and_svg_outputs[fr] - KeyError:... FAILED tools/test_narrative.py::test_pdf_html_and_svg_outputs[es] - KeyError:... FAILED tools/test_narrative.py::test_pdf_html_and_svg_outputs[it] - KeyError:... FAILED tools/test_narrative.py::test_pdf_html_and_svg_outputs[pt] - KeyError:... FAILED tools/test_narrative.py::test_pdf_html_and_svg_outputs[nl] - KeyError:... FAILED tools/test_narrative.py::test_pdf_html_and_svg_outputs[pl] - KeyError:... FAILED tools/test_narrative.py::test_pdf_html_and_svg_outputs[cs] - KeyError:... FAILED tools/test_narrative.py::test_pdf_html_and_svg_outputs[sk] - KeyError:... FAILED tools/test_narrative.py::test_pdf_html_and_svg_outputs[uk] - KeyError:... FAILED tools/test_narrative.py::test_pdf_html_and_svg_outputs[ro] - KeyError:... FAILED tools/test_narrative.py::test_pdf_html_and_svg_outputs[bg] - KeyError:... FAILED tools/test_narrative.py::test_pdf_html_and_svg_outputs[hu] - KeyError:... FAILED tools/test_narrative.py::test_pdf_html_and_svg_outputs[el] - KeyError:... FAILED tools/test_narrative.py::test_pdf_html_and_svg_outputs[sv] - KeyError:... FAILED tools/test_narrative.py::test_pdf_html_and_svg_outputs[da] - KeyError:... FAILED tools/test_narrative.py::test_pdf_html_and_svg_outputs[fi] - KeyError:... FAILED tools/test_narrative.py::test_pdf_html_and_svg_outputs[no] - KeyError:... FAILED tools/test_narrative.py::test_pdf_html_and_svg_outputs[lt] - KeyError:... FAILED tools/test_narrative.py::test_pdf_html_and_svg_outputs[lv] - KeyError:... FAILED tools/test_narrative.py::test_pdf_html_and_svg_outputs[et] - KeyError:... FAILED tools/test_narrative.py::test_pdf_html_and_svg_outputs[tr] - KeyError:... FAILED tools/test_narrative.py::test_pdf_html_and_svg_outputs[ja] - KeyError:... FAILED tools/test_narrative.py::test_pdf_html_and_svg_outputs[zh] - KeyError:... FAILED tools/test_narrative.py::test_pdf_html_and_svg_outputs[zh-Hant] - KeyE... FAILED tools/test_narrative.py::test_pdf_html_and_svg_outputs[ko] - KeyError:... FAILED tools/test_narrative.py::test_pdf_html_and_svg_outputs[ar] - KeyError:... FAILED tools/test_narrative.py::test_pdf_html_and_svg_outputs[he] - KeyError:... FAILED tools/test_narrative.py::test_pdf_html_and_svg_outputs[fa] - KeyError:... FAILED tools/test_narrative.py::test_pdf_html_and_svg_outputs[hi] - KeyError:... FAILED tools/test_narrative.py::test_pdf_html_and_svg_outputs[ur] - KeyError:... FAILED tools/test_narrative.py::test_pdf_html_and_svg_outputs[bn] - KeyError:... FAILED tools/test_narrative.py::test_pdf_html_and_svg_outputs[id] - KeyError:... FAILED tools/test_narrative.py::test_pdf_html_and_svg_outputs[ms] - KeyError:... FAILED tools/test_narrative.py::test_pdf_html_and_svg_outputs[vi] - KeyError:... FAILED tools/test_narrative.py::test_pdf_html_and_svg_outputs[th] - KeyError:... FAILED tools/test_narrative.py::test_pdf_html_and_svg_outputs[uz] - KeyError:... FAILED tools/test_narrative.py::test_pdf_html_and_svg_outputs[ru] - KeyError:... FAILED tools/test_narrative.py::test_jurisdictions_change_only_the_terms_section FAILED tools/test_narrative.py::test_catalog_policy_and_plural_edge_cases - F... FAILED tools/test_narrative.py::test_golden_model_is_language_independent - A... FAILED tools/test_narrative_config.py::test_optional_diagrams_cannot_hide_assurance_limits_or_references[selected0] FAILED tools/test_narrative_config.py::test_optional_diagrams_cannot_hide_assurance_limits_or_references[selected1] FAILED tools/test_narrative_config.py::test_optional_diagrams_cannot_hide_assurance_limits_or_references[selected2] FAILED tools/test_secret_chat_safety.py::test_allowed_close_is_sent_and_journaled FAILED tools/test_session_import.py::test_independent_login_browser[False] - ... FAILED tools/test_session_import.py::test_independent_login_browser[True] - p... FAILED tools/test_verifier_comparison.py::test_ots_structure_only_does_not_get_a_positive_indicator[unknown] FAILED tools/test_verifier_dispatch.py::test_direct_check_preserves_policy_and_archive_without_printing[tgwitness.verify] FAILED tools/test_verifier_dispatch.py::test_direct_check_preserves_policy_and_archive_without_printing[tgwitness.verifier.cli] FAILED tools/test_verifier_sources.py::test_review_modules_import_without_application_state FAILED tools/test_verifier_sources.py::test_frozen_verification_decisions_are_unchanged FAILED tools/test_verifier_sources.py::test_old_and_new_decisions_and_statuses_match[pinned---json] FAILED tools/test_verifier_sources.py::test_old_and_new_decisions_and_statuses_match[pinned---plain] FAILED tools/test_verifier_sources.py::test_old_and_new_decisions_and_statuses_match[unpinned---json] FAILED tools/test_verifier_sources.py::test_old_and_new_decisions_and_statuses_match[unpinned---plain] FAILED tools/test_verifier_sources.py::test_old_and_new_decisions_and_statuses_match[unmet_tier---json] FAILED tools/test_verifier_sources.py::test_old_and_new_decisions_and_statuses_match[unmet_tier---plain] FAILED tools/test_verifier_sources.py::test_old_verifier_accepts_new_archive_with_identical_signed_events FAILED tools/test_watchlists.py::test_terms_patterns_wallets_usernames_and_domains_are_matched FAILED addons/capture/tests/test_trusted_anchors.py::test_cloudflare_queries_are_read_only_scoped_and_token_is_not_exported 79 failed, 1912 passed, 35 skipped, 51 warnings, 18 subtests passed in 637.04s (0:10:37)