<?xml version="1.0" encoding="utf-8"?><testsuites name="pytest tests"><testsuite name="pytest" errors="0" failures="79" skipped="35" tests="2044" time="658.913" timestamp="2026-11-14T06:24:13.301135+00:00" hostname="30dadb93af88"><testcase classname="tools.test_access_label_privacy" name="test_new_access_events_omit_names_while_historical_signed_rows_remain_unchanged" file="tools/test_access_label_privacy.py" line="14" time="0.359" /><testcase classname="tools.test_access_label_privacy" name="test_existing_grants_supply_names_when_loading_a_legacy_vault" file="tools/test_access_label_privacy.py" line="47" time="0.212" /><testcase classname="tools.test_access_label_privacy" name="test_access_name_mapping_is_admin_only_and_profile_creation_keeps_ids[permissions0-None]" file="tools/test_access_label_privacy.py" line="66" time="2.131" /><testcase classname="tools.test_access_label_privacy" name="test_access_name_mapping_is_admin_only_and_profile_creation_keeps_ids[permissions1-chats1]" file="tools/test_access_label_privacy.py" line="66" time="1.477" /><testcase classname="tools.test_access_label_privacy" name="test_access_name_mapping_is_admin_only_and_profile_creation_keeps_ids[permissions2-None]" file="tools/test_access_label_privacy.py" line="66" time="1.236" /><testcase classname="tools.test_account_attachment_integrity" name="test_photo_download_uses_the_hash_manifest_variant[None-False]" file="tools/test_account_attachment_integrity.py" line="34" time="0.001" /><testcase classname="tools.test_account_attachment_integrity" name="test_photo_download_uses_the_hash_manifest_variant[None-True]" file="tools/test_account_attachment_integrity.py" line="34" time="0.001" /><testcase classname="tools.test_account_attachment_integrity" name="test_photo_download_uses_the_hash_manifest_variant[999-False]" file="tools/test_account_attachment_integrity.py" line="34" time="0.001" /><testcase classname="tools.test_account_attachment_integrity" name="test_photo_download_uses_the_hash_manifest_variant[999-True]" file="tools/test_account_attachment_integrity.py" line="34" time="0.001" /><testcase classname="tools.test_account_attachment_integrity" name="test_photo_reference_refresh_keeps_the_observed_representation[none]" file="tools/test_account_attachment_integrity.py" line="59" time="0.000" /><testcase classname="tools.test_account_attachment_integrity" name="test_photo_reference_refresh_keeps_the_observed_representation[variant]" file="tools/test_account_attachment_integrity.py" line="59" time="0.000" /><testcase classname="tools.test_account_attachment_integrity" name="test_photo_reference_refresh_keeps_the_observed_representation[size]" file="tools/test_account_attachment_integrity.py" line="59" time="0.001" /><testcase classname="tools.test_account_attachment_integrity" name="test_account_photo_length_controls_archive_coverage[]" file="tools/test_account_attachment_integrity.py" line="95" time="0.803" /><testcase classname="tools.test_account_attachment_integrity" name="test_account_photo_length_controls_archive_coverage[012345678]" file="tools/test_account_attachment_integrity.py" line="95" time="0.672" /><testcase classname="tools.test_account_attachment_integrity" name="test_account_photo_length_controls_archive_coverage[0123456789]" file="tools/test_account_attachment_integrity.py" line="95" time="0.660" /><testcase classname="tools.test_account_attachment_integrity" name="test_verifier_rejects_signed_payload_length_contradictions[expected_bytes]" file="tools/test_account_attachment_integrity.py" line="134" time="0.631" /><testcase classname="tools.test_account_attachment_integrity" name="test_verifier_rejects_signed_payload_length_contradictions[representation]" file="tools/test_account_attachment_integrity.py" line="134" time="0.636" /><testcase classname="tools.test_account_attachment_integrity" name="test_chat_export_rejects_incomplete_payload[]" file="tools/test_account_attachment_integrity.py" line="167" time="0.199" /><testcase classname="tools.test_account_attachment_integrity" name="test_chat_export_rejects_incomplete_payload[012345678]" file="tools/test_account_attachment_integrity.py" line="167" time="0.190" /><testcase classname="tools.test_account_attachment_integrity" name="test_chat_export_rejects_incomplete_payload[0123456789]" file="tools/test_account_attachment_integrity.py" line="167" time="0.187" /><testcase classname="tools.test_account_attachment_integrity" name="test_chat_export_rejects_corrupt_existing_content" file="tools/test_account_attachment_integrity.py" line="194" time="0.184" /><testcase classname="tools.test_action_protocol" name="test_bot_start_reads_as_one_protocol_with_reply_delay_files_and_indicators" file="tools/test_action_protocol.py" line="49" time="0.001" /><testcase classname="tools.test_action_protocol" name="test_messages_after_the_window_or_limit_are_counted_not_listed" file="tools/test_action_protocol.py" line="66" time="0.000" /><testcase classname="tools.test_action_protocol" name="test_button_press_lists_the_bot_edit_and_the_callback_answer" file="tools/test_action_protocol.py" line="78" time="0.000" /><testcase classname="tools.test_action_protocol" name="test_chat_restriction_excludes_other_chats_and_actions_without_a_chat" file="tools/test_action_protocol.py" line="91" time="0.001" /><testcase classname="tools.test_action_protocol" name="test_isolated_browser_capture_is_a_step_with_an_honest_caption_and_picture" file="tools/test_action_protocol.py" line="101" time="0.000" /><testcase classname="tools.test_action_protocol" name="test_rendered_protocol_escapes_message_text_and_cites_records" file="tools/test_action_protocol.py" line="120" time="0.000" /><testcase classname="tools.test_action_protocol" name="test_collect_reads_actions_and_replies_from_a_signed_store" file="tools/test_action_protocol.py" line="129" time="0.198" /><testcase classname="tools.test_action_protocol" name="test_operator_account_changes_and_ai_drafts_are_shown_not_omitted" file="tools/test_action_protocol.py" line="150" time="0.003" /><testcase classname="tools.test_action_protocol" name="test_documentation_includes_account_changes_for_full_access" file="tools/test_action_protocol.py" line="190" time="0.237" /><testcase classname="tools.test_analyzer_graphs" name="test_edges_cite_journal_records_across_chosen_chats" file="tools/test_analyzer_graphs.py" line="53" time="0.236"><failure message="assert False&#10; +  where False = any(&lt;generator object test_edges_cite_journal_records_across_chosen_chats.&lt;locals&gt;.&lt;genexpr&gt; at 0x747f85b18380&gt;)">store = (&lt;tgwitness.store.Store object at 0x747f874a3c80&gt;, {'pay': {'seq': 1, 'observed_at': '2026-11-14T06:24:27.087+00:00', ...ward': {'seq': 4, 'observed_at': '2026-11-14T06:24:27.117+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 &lt;b&gt;&amp;" and nodes["account:11"]["messages"] == 2
        assert nodes["account:11"]["community"] == nodes["account:22"]["community"]
        assert all(len(e["refs"]) &lt;= graphs.MAX_REFS for e in model["edges"]) and not model["truncated"]
&gt;       assert any("does not mean there was no contact" in line for line in model["limits"])
E       assert False
E        +  where False = any(&lt;generator object test_edges_cite_journal_records_across_chosen_chats.&lt;locals&gt;.&lt;genexpr&gt; at 0x747f85b18380&gt;)

tools/test_analyzer_graphs.py:71: AssertionError</failure></testcase><testcase classname="tools.test_analyzer_graphs" name="test_svg_is_deterministic_escaped_and_script_free" file="tools/test_analyzer_graphs.py" line="75" time="0.244" /><testcase classname="tools.test_analyzer_graphs" name="test_gexf_is_valid_and_carries_record_references" file="tools/test_analyzer_graphs.py" line="87" time="0.269" /><testcase classname="tools.test_analyzer_graphs" name="test_routes_check_every_chat_and_refuse_witness_workspaces" file="tools/test_analyzer_graphs.py" line="118" time="0.301" /><testcase classname="tools.test_analyzer_linking" name="test_rotated_account_ranks_first_with_explanation_and_citations" file="tools/test_analyzer_linking.py" line="65" time="0.671"><failure message="assert False&#10; +  where False = any(&lt;generator object test_rotated_account_ranks_first_with_explanation_and_citations.&lt;locals&gt;.&lt;genexpr&gt; at 0x747f855eadc0&gt;)">reader = &lt;tgwitness.extensions.JournalReader object at 0x747f87fd9160&gt;

    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"] &gt; pair["score"] for pair in result["pairs"][1:])
        assert {"lexical", "hours", "handoff", "shared"} &lt;= 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")
&gt;       assert any("not identification" in line for line in result["limits"])
E       assert False
E        +  where False = any(&lt;generator object test_rotated_account_ranks_first_with_explanation_and_citations.&lt;locals&gt;.&lt;genexpr&gt; at 0x747f855eadc0&gt;)

tools/test_analyzer_linking.py:81: AssertionError</failure></testcase><testcase classname="tools.test_analyzer_linking" name="test_thin_accounts_and_own_messages_are_not_compared" file="tools/test_analyzer_linking.py" line="83" time="0.679" /><testcase classname="tools.test_analyzer_linking" name="test_ranked_basis_on_a_larger_population" file="tools/test_analyzer_linking.py" line="90" time="0.021" /><testcase classname="tools.test_anchor_backoff" name="test_repeated_rate_limits_back_off_and_success_clears_the_wait" file="tools/test_anchor_backoff.py" line="42" time="0.447" /><testcase classname="tools.test_anchor_backoff" name="test_retry_after_is_honoured_and_deferred_services_are_reported" file="tools/test_anchor_backoff.py" line="71" time="0.321" /><testcase classname="tools.test_anchor_backoff" name="test_health_stays_degraded_while_a_service_waits" file="tools/test_anchor_backoff.py" line="93" time="0.000" /><testcase classname="tools.test_anchor_backoff" name="test_retry_after_accepts_http_dates_and_caps_long_waits" file="tools/test_anchor_backoff.py" line="106" time="0.000" /><testcase classname="tools.test_anchor_temp_files" name="test_evidence_export_skips_proofs_being_written" file="tools/test_anchor_temp_files.py" line="10" time="1.159" /><testcase classname="tools.test_api_authorization_matrix" name="test_all_api_routes_reject_anonymous_and_revoked_access" file="tools/test_api_authorization_matrix.py" line="19" time="2.588"><properties><property name="routes_checked" value="374" /><property name="requests_checked" value="748" /></properties></testcase><testcase classname="tools.test_api_authorization_matrix" name="test_replica_recovery_key_requires_administrator" file="tools/test_api_authorization_matrix.py" line="57" time="0.706" /><testcase classname="tools.test_api_refactor" name="test_application_factory_contains_no_route_closures" file="tools/test_api_refactor.py" line="21" time="0.001" /><testcase classname="tools.test_api_refactor" name="test_route_audit_includes_endpoints_inside_native_routers" file="tools/test_api_refactor.py" line="29" time="0.463" /><testcase classname="tools.test_api_refactor" name="test_domain_endpoints_import_without_constructing_application" file="tools/test_api_refactor.py" line="37" time="0.556" /><testcase classname="tools.test_api_refactor" name="test_endpoint_accepts_explicit_context_without_application" file="tools/test_api_refactor.py" line="48" time="0.001" /><testcase classname="tools.test_api_refactor" name="test_account_operation_keeps_explicit_context_guard" file="tools/test_api_refactor.py" line="55" time="0.000" /><testcase classname="tools.test_api_refactor" name="test_registered_authenticator_supports_direct_reauthorization[True]" file="tools/test_api_refactor.py" line="69" time="0.468" /><testcase classname="tools.test_api_refactor" name="test_registered_authenticator_supports_direct_reauthorization[False]" file="tools/test_api_refactor.py" line="69" time="0.124" /><testcase classname="tools.test_api_refactor" name="test_profile_dispatch_uses_its_own_context_and_scope[root]" file="tools/test_api_refactor.py" line="87" time="1.307" /><testcase classname="tools.test_api_refactor" name="test_profile_dispatch_uses_its_own_context_and_scope[child]" file="tools/test_api_refactor.py" line="87" time="1.701" /><testcase classname="tools.test_archive_token_comparison" name="test_archive_credential_checks_every_digest_regardless_of_match[0]" file="tools/test_archive_token_comparison.py" line="13" time="0.040" /><testcase classname="tools.test_archive_token_comparison" name="test_archive_credential_checks_every_digest_regardless_of_match[1]" file="tools/test_archive_token_comparison.py" line="13" time="0.052" /><testcase classname="tools.test_archive_token_comparison" name="test_archive_credential_checks_every_digest_regardless_of_match[2]" file="tools/test_archive_token_comparison.py" line="13" time="0.039" /><testcase classname="tools.test_archive_token_comparison" name="test_archive_credential_checks_every_digest_regardless_of_match[None]" file="tools/test_archive_token_comparison.py" line="13" time="0.038" /><testcase classname="tools.test_archive_views" name="test_day_bounds_follow_daylight_saving" file="tools/test_archive_views.py" line="66" time="0.002" /><testcase classname="tools.test_archive_views" name="test_messages_of_one_day_use_telegram_time" file="tools/test_archive_views.py" line="75" time="0.305" /><testcase classname="tools.test_archive_views" name="test_pinned_messages_and_pin_notices" file="tools/test_archive_views.py" line="87" time="0.387" /><testcase classname="tools.test_archive_views" name="test_chat_counts_carry_gap_summary_within_access" file="tools/test_archive_views.py" line="95" time="0.334" /><testcase classname="tools.test_archive_views" name="test_topics_come_from_saved_service_messages" file="tools/test_archive_views.py" line="106" time="0.336" /><testcase classname="tools.test_archive_views" name="test_chat_counts_reconstruct_compact_snapshots" file="tools/test_archive_views.py" line="115" time="0.350" /><testcase classname="tools.test_archive_views" name="test_topics_include_references_without_creation_and_ignore_replayed_history" file="tools/test_archive_views.py" line="125" time="0.343" /><testcase classname="tools.test_archive_views" name="test_date_scan_can_resume_after_a_page_with_no_matching_messages" file="tools/test_archive_views.py" line="136" time="3.415" /><testcase classname="tools.test_archive_views" name="test_media_preview_is_bounded_verified_and_scoped" file="tools/test_archive_views.py" line="158" time="0.338" /><testcase classname="tools.test_archive_views" name="test_unreadable_or_large_images_return_metadata" file="tools/test_archive_views.py" line="174" time="0.326" /><testcase classname="tools.test_archive_views" name="test_topic_listing_marks_truncation" file="tools/test_archive_views.py" line="185" time="0.825" /><testcase classname="tools.test_archive_views" name="test_every_mcp_tool_declares_output_and_media_returns_an_image" file="tools/test_archive_views.py" line="197" time="0.403" /><testcase classname="tools.test_assurance_boundaries" name="test_capture_failures_do_not_remain_continuous[collector.error-payload0]" file="tools/test_assurance_boundaries.py" line="40" time="0.001" /><testcase classname="tools.test_assurance_boundaries" name="test_capture_failures_do_not_remain_continuous[connection.closed-payload1]" file="tools/test_assurance_boundaries.py" line="40" time="0.000" /><testcase classname="tools.test_assurance_boundaries" name="test_capture_failures_do_not_remain_continuous[collector.heartbeat-payload2]" file="tools/test_assurance_boundaries.py" line="40" time="0.000" /><testcase classname="tools.test_assurance_boundaries" name="test_only_capture_liveness_can_extend_or_resume_observation[parameters.changed-payload0]" file="tools/test_assurance_boundaries.py" line="54" time="0.000" /><testcase classname="tools.test_assurance_boundaries" name="test_only_capture_liveness_can_extend_or_resume_observation[message.snapshot-payload1]" file="tools/test_assurance_boundaries.py" line="54" time="0.000" /><testcase classname="tools.test_assurance_boundaries" name="test_only_capture_liveness_can_extend_or_resume_observation[host.state-payload2]" file="tools/test_assurance_boundaries.py" line="54" time="0.000" /><testcase classname="tools.test_assurance_boundaries" name="test_only_capture_liveness_can_extend_or_resume_observation[media.saved-payload3]" file="tools/test_assurance_boundaries.py" line="54" time="0.000" /><testcase classname="tools.test_assurance_boundaries" name="test_only_capture_liveness_can_extend_or_resume_observation[collector.heartbeat-payload4]" file="tools/test_assurance_boundaries.py" line="54" time="0.000" /><testcase classname="tools.test_assurance_boundaries" name="test_late_connection_and_heartbeat_cannot_undo_a_stop[observation.stopped]" file="tools/test_assurance_boundaries.py" line="65" time="0.000" /><testcase classname="tools.test_assurance_boundaries" name="test_late_connection_and_heartbeat_cannot_undo_a_stop[process.stopped]" file="tools/test_assurance_boundaries.py" line="65" time="0.000" /><testcase classname="tools.test_assurance_boundaries" name="test_late_connection_and_heartbeat_cannot_undo_a_stop[process.started]" file="tools/test_assurance_boundaries.py" line="65" time="0.000" /><testcase classname="tools.test_assurance_boundaries" name="test_confirmed_recovery_and_explicit_restart_can_resume" file="tools/test_assurance_boundaries.py" line="74" time="0.000" /><testcase classname="tools.test_assurance_boundaries" name="test_nonfatal_error_records_uncertainty_until_the_next_capture_heartbeat" file="tools/test_assurance_boundaries.py" line="86" time="0.000" /><testcase classname="tools.test_assurance_boundaries" name="test_candidate_connection_close_does_not_stop_current_capture" file="tools/test_assurance_boundaries.py" line="95" time="0.000" /><testcase classname="tools.test_assurance_boundaries" name="test_real_supervisor_failure_and_signed_bundle[False-False]" file="tools/test_assurance_boundaries.py" line="101" time="0.323" /><testcase classname="tools.test_assurance_boundaries" name="test_real_supervisor_failure_and_signed_bundle[False-True]" file="tools/test_assurance_boundaries.py" line="101" time="0.304" /><testcase classname="tools.test_assurance_boundaries" name="test_real_supervisor_failure_and_signed_bundle[False-stop_only]" file="tools/test_assurance_boundaries.py" line="101" time="0.320" /><testcase classname="tools.test_assurance_boundaries" name="test_real_supervisor_failure_and_signed_bundle[True-False]" file="tools/test_assurance_boundaries.py" line="101" time="0.326" /><testcase classname="tools.test_assurance_boundaries" name="test_real_supervisor_failure_and_signed_bundle[True-True]" file="tools/test_assurance_boundaries.py" line="101" time="0.282" /><testcase classname="tools.test_assurance_boundaries" name="test_real_supervisor_failure_and_signed_bundle[True-stop_only]" file="tools/test_assurance_boundaries.py" line="101" time="0.325" /><testcase classname="tools.test_assurance_boundaries" name="test_comparison_does_not_confuse_matching_with_equal_content[text_tail-1]" file="tools/test_assurance_boundaries.py" line="169" time="0.030" /><testcase classname="tools.test_assurance_boundaries" name="test_comparison_does_not_confuse_matching_with_equal_content[text_tail-2]" file="tools/test_assurance_boundaries.py" line="169" time="0.024" /><testcase classname="tools.test_assurance_boundaries" name="test_comparison_does_not_confuse_matching_with_equal_content[entities-1]" file="tools/test_assurance_boundaries.py" line="169" time="0.024" /><testcase classname="tools.test_assurance_boundaries" name="test_comparison_does_not_confuse_matching_with_equal_content[entities-2]" file="tools/test_assurance_boundaries.py" line="169" time="0.022" /><testcase classname="tools.test_assurance_boundaries" name="test_comparison_does_not_confuse_matching_with_equal_content[caption-1]" file="tools/test_assurance_boundaries.py" line="169" time="0.024" /><testcase classname="tools.test_assurance_boundaries" name="test_comparison_does_not_confuse_matching_with_equal_content[caption-2]" file="tools/test_assurance_boundaries.py" line="169" time="0.022" /><testcase classname="tools.test_assurance_boundaries" name="test_comparison_does_not_confuse_matching_with_equal_content[reply-1]" file="tools/test_assurance_boundaries.py" line="169" time="0.024" /><testcase classname="tools.test_assurance_boundaries" name="test_comparison_does_not_confuse_matching_with_equal_content[reply-2]" file="tools/test_assurance_boundaries.py" line="169" time="0.024" /><testcase classname="tools.test_assurance_boundaries" name="test_comparison_does_not_confuse_matching_with_equal_content[sender-1]" file="tools/test_assurance_boundaries.py" line="169" time="0.026" /><testcase classname="tools.test_assurance_boundaries" name="test_comparison_does_not_confuse_matching_with_equal_content[sender-2]" file="tools/test_assurance_boundaries.py" line="169" time="0.022" /><testcase classname="tools.test_assurance_boundaries" name="test_candidate_matches_compare_record_ids_and_timestamps" file="tools/test_assurance_boundaries.py" line="196" time="0.027" /><testcase classname="tools.test_assurance_boundaries" name="test_signed_chat_cannot_silently_skip_records[compact]" file="tools/test_assurance_boundaries.py" line="207" time="0.024" /><testcase classname="tools.test_assurance_boundaries" name="test_signed_chat_cannot_silently_skip_records[count]" file="tools/test_assurance_boundaries.py" line="207" time="0.029" /><testcase classname="tools.test_assurance_boundaries" name="test_signed_chat_cannot_silently_skip_records[duplicate]" file="tools/test_assurance_boundaries.py" line="207" time="0.026" /><testcase classname="tools.test_assurance_boundaries" name="test_signed_chat_cannot_silently_skip_records[invalid_row]" file="tools/test_assurance_boundaries.py" line="207" time="0.024" /><testcase classname="tools.test_assurance_boundaries" name="test_signed_chat_cannot_silently_skip_records[trailing_comma]" file="tools/test_assurance_boundaries.py" line="207" time="0.024" /><testcase classname="tools.test_assurance_boundaries" name="test_signed_chat_cannot_silently_skip_records[tail]" file="tools/test_assurance_boundaries.py" line="207" time="0.024" /><testcase classname="tools.test_assurance_chain" name="test_cli_requires_actual_daily_proof_for_witness_anchored[confirmed-0]" file="tools/test_assurance_chain.py" line="21" time="0.586" /><testcase classname="tools.test_assurance_chain" name="test_cli_requires_actual_daily_proof_for_witness_anchored[missing-2]" file="tools/test_assurance_chain.py" line="21" time="0.642" /><testcase classname="tools.test_assurance_chain" name="test_cli_requires_actual_daily_proof_for_witness_anchored[mismatch-1]" file="tools/test_assurance_chain.py" line="21" time="0.581" /><testcase classname="tools.test_assurance_ladder" name="test_all_lower_steps_must_pass_and_seal_cannot_be_inferred" file="tools/test_assurance_ladder.py" line="23" time="0.000" /><testcase classname="tools.test_assurance_ladder" name="test_witness_requires_pin_independent_key_and_exact_head[change0]" file="tools/test_assurance_ladder.py" line="33" time="0.000" /><testcase classname="tools.test_assurance_ladder" name="test_witness_requires_pin_independent_key_and_exact_head[change1]" file="tools/test_assurance_ladder.py" line="33" time="0.000" /><testcase classname="tools.test_assurance_ladder" name="test_witness_requires_pin_independent_key_and_exact_head[change2]" file="tools/test_assurance_ladder.py" line="33" time="0.000" /><testcase classname="tools.test_assurance_ladder" name="test_unconfirmed_or_partial_timestamp_does_not_count" file="tools/test_assurance_ladder.py" line="41" time="0.000" /><testcase classname="tools.test_assurance_ladder" name="test_missing_days_are_absent_and_contradictions_fail" file="tools/test_assurance_ladder.py" line="49" time="0.000" /><testcase classname="tools.test_assurance_ladder" name="test_only_checked_runtime_with_created_key_can_reach_sealed" file="tools/test_assurance_ladder.py" line="58" time="0.000" /><testcase classname="tools.test_assurance_ladder" name="test_cli_legacy_and_required_tier_exit_codes" file="tools/test_assurance_ladder.py" line="66" time="0.468" /><testcase classname="tools.test_audit_logic_repairs" name="test_existing_media_is_verified_and_corrupt_bytes_retained[None]" file="tools/test_audit_logic_repairs.py" line="22" time="0.279" /><testcase classname="tools.test_audit_logic_repairs" name="test_existing_media_is_verified_and_corrupt_bytes_retained[valid attachment]" file="tools/test_audit_logic_repairs.py" line="22" time="0.262" /><testcase classname="tools.test_audit_logic_repairs" name="test_existing_media_is_verified_and_corrupt_bytes_retained[damaged attachment]" file="tools/test_audit_logic_repairs.py" line="22" time="0.275" /><testcase classname="tools.test_audit_logic_repairs" name="test_nonregular_media_destination_cannot_receive_a_success_receipt[directory]" file="tools/test_audit_logic_repairs.py" line="51" time="0.252" /><testcase classname="tools.test_audit_logic_repairs" name="test_nonregular_media_destination_cannot_receive_a_success_receipt[symlink]" file="tools/test_audit_logic_repairs.py" line="51" time="0.254" /><testcase classname="tools.test_audit_logic_repairs" name="test_retry_runs_without_a_reconnect" file="tools/test_audit_logic_repairs.py" line="79" time="5.311" /><testcase classname="tools.test_audit_logic_repairs" name="test_deferral_is_retried_and_transfers_are_serial" file="tools/test_audit_logic_repairs.py" line="104" time="5.324" /><testcase classname="tools.test_audit_logic_repairs" name="test_detach_keeps_the_current_and_waiting_transfers" file="tools/test_audit_logic_repairs.py" line="143" time="0.293" /><testcase classname="tools.test_audit_logic_repairs" name="test_browser_ids_are_exact_without_rewriting_signed_records" file="tools/test_audit_logic_repairs.py" line="168" time="0.269" /><testcase classname="tools.test_audit_logic_repairs" name="test_history_cursors_cover_every_record_without_gaps" file="tools/test_audit_logic_repairs.py" line="185" time="0.938" /><testcase classname="tools.test_audit_logic_repairs" name="test_concurrent_report_edits_preserve_revisions_or_return_conflict[None]" file="tools/test_audit_logic_repairs.py" line="210" time="0.748" /><testcase classname="tools.test_audit_logic_repairs" name="test_concurrent_report_edits_preserve_revisions_or_return_conflict[0]" file="tools/test_audit_logic_repairs.py" line="210" time="1.264" /><testcase classname="tools.test_audit_logic_repairs" name="test_report_revision_input_rejects_negative_values" file="tools/test_audit_logic_repairs.py" line="253" time="0.000" /><testcase classname="tools.test_audit_platform_fixes" name="test_main_account_scope_is_checked_before_changes" file="tools/test_audit_platform_fixes.py" line="27" time="0.922" /><testcase classname="tools.test_audit_platform_fixes" name="test_route_only_group_adoption_does_not_claim_applied" file="tools/test_audit_platform_fixes.py" line="68" time="0.703" /><testcase classname="tools.test_audit_platform_fixes" name="test_rclone_token_replacement_keeps_recovery" file="tools/test_audit_platform_fixes.py" line="89" time="0.445" /><testcase classname="tools.test_audit_platform_fixes" name="test_replica_restore_coexists_with_ordinary_s3_storage" file="tools/test_audit_platform_fixes.py" line="143" time="0.469" /><testcase classname="tools.test_audit_platform_fixes" name="test_partial_notification_retry_is_per_destination" file="tools/test_audit_platform_fixes.py" line="172" time="0.546" /><testcase classname="tools.test_audit_platform_fixes" name="test_notification_route_isolated_from_unrelated_threads" file="tools/test_audit_platform_fixes.py" line="220" time="0.002" /><testcase classname="tools.test_audit_platform_fixes" name="test_deployment_record_replacement_failure_preserves_inventory" file="tools/test_audit_platform_fixes.py" line="235" time="0.034" /><testcase classname="tools.test_audit_platform_fixes" name="test_versioned_measurement_includes_resources_and_preserves_legacy" file="tools/test_audit_platform_fixes.py" line="247" time="0.008" /><testcase classname="tools.test_audit_platform_fixes" name="test_package_measurement_matches_declared_wheel_inventory" file="tools/test_audit_platform_fixes.py" line="289" time="0.110" /><testcase classname="tools.test_auto_delete_classification" name="test_notice_within_window_is_the_timer" file="tools/test_auto_delete_classification.py" line="13" time="0.000" /><testcase classname="tools.test_auto_delete_classification" name="test_late_notice_after_reconnect_is_attributed_to_the_timer_with_its_delay" file="tools/test_auto_delete_classification.py" line="18" time="0.000" /><testcase classname="tools.test_auto_delete_classification" name="test_notice_well_before_expiry_is_a_deletion" file="tools/test_auto_delete_classification.py" line="24" time="0.000" /><testcase classname="tools.test_auto_delete_classification" name="test_recheck_classification_is_unchanged" file="tools/test_auto_delete_classification.py" line="29" time="0.000" /><testcase classname="tools.test_auto_delete_classification" name="test_messages_without_a_timer_are_not_classified" file="tools/test_auto_delete_classification.py" line="34" time="0.000" /><testcase classname="tools.test_capture_liveness" name="test_worker_failure_closes_signed_capture_before_cleanup" file="tools/test_capture_liveness.py" line="20" time="1.551" /><testcase classname="tools.test_capture_liveness" name="test_administrative_and_backfill_records_do_not_keep_capture_alive[parameters.changed]" file="tools/test_capture_liveness.py" line="49" time="0.000" /><testcase classname="tools.test_capture_liveness" name="test_administrative_and_backfill_records_do_not_keep_capture_alive[message.snapshot]" file="tools/test_capture_liveness.py" line="49" time="0.000" /><testcase classname="tools.test_capture_liveness" name="test_administrative_and_backfill_records_do_not_keep_capture_alive[media.downloaded]" file="tools/test_capture_liveness.py" line="49" time="0.000" /><testcase classname="tools.test_capture_liveness" name="test_administrative_and_backfill_records_do_not_keep_capture_alive[checkpoint.created]" file="tools/test_capture_liveness.py" line="49" time="0.000" /><testcase classname="tools.test_capture_liveness" name="test_current_disconnect_closes_legacy_capture_but_candidate_disconnect_does_not" file="tools/test_capture_liveness.py" line="62" time="0.000" /><testcase classname="tools.test_capture_liveness" name="test_explicit_stop_is_not_resumed_by_stray_heartbeat_or_disconnect" file="tools/test_capture_liveness.py" line="75" time="0.000" /><testcase classname="tools.test_capture_open" name="test_signed_capture_is_linked_in_the_panel_journal" file="tools/test_capture_open.py" line="45" time="0.332" /><testcase classname="tools.test_capture_open" name="test_tampered_or_replayed_recorder_answers_are_refused" file="tools/test_capture_open.py" line="59" time="0.371" /><testcase classname="tools.test_case_package" name="test_package_contains_readable_report_files_and_explanations[tsr]" file="tools/test_case_package.py" line="31" time="0.295"><failure message="assert ('Timestamp receipts (not verified)' in '&lt;!doctype html&gt;&lt;html lang=&quot;en&quot;&gt;&lt;meta charset=&quot;utf-8&quot;&gt;&lt;meta http-equiv=&quot;Content-Security-Policy&quot; content=&quot;default-src ...lank&quot;&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;Date: &lt;span class=&quot;blank&quot;&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;Place: &lt;span class=&quot;blank&quot;&gt;&lt;/span&gt;&lt;/p&gt;&lt;/div&gt;&lt;/body&gt;&lt;/html&gt;')">tmp_path = PosixPath('/tmp/pytest-of-root/pytest-6/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('&lt;section class="slide') &gt;= 5 and "Isolated browser capture" in slides and "explicit" not in slides
                payload = {"documentation.json", "report.html", "presentation.html", "verification.html", "indicators.csv",
                           "indicators.stix.json", "files/" + sha(PHOTO) + ".jpg", "files/" + sha(SCREEN) + ".png",
                           "timestamps/" + name + ".json", "timestamps/" + receipt_name,
                           "court/certification.html", "court/exhibits.html", "court/exhibits.csv", "court/request-annex.html",
                           "court/request-annex.csv", "court/request-annex.json", "court/undercover-record.html",
                           "court/undercover-record.json"}
                tags = {"bagit.txt", "bag-info.txt", "manifest-sha256.txt", "tagmanifest-sha256.txt", "README.txt"}
                assert names == {root + "data/" + p for p in payload} | {root + t for t in tags}
                certificate = archive.read(root + "data/court/certification.html").decode()
                for member in payload - {"court/certification.html"}:
                    digest = hashlib.sha256(archive.read(root + "data/" + member)).hexdigest()
                    assert digest in certificate and "data/" + member in certificate
                assert fixed["statement_sha256"] in certificate and "explicit" not in certificate
&gt;               assert "Timestamp receipts (not verified)" in certificate and "have not been verified" in certificate
E               assert ('Timestamp receipts (not verified)' in '&lt;!doctype html&gt;&lt;html lang="en"&gt;&lt;meta charset="utf-8"&gt;&lt;meta http-equiv="Content-Security-Policy" content="default-src ...lank"&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;Date: &lt;span class="blank"&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;Place: &lt;span class="blank"&gt;&lt;/span&gt;&lt;/p&gt;&lt;/div&gt;&lt;/body&gt;&lt;/html&gt;')

tools/test_case_package.py:82: AssertionError</failure></testcase><testcase classname="tools.test_case_package" name="test_package_contains_readable_report_files_and_explanations[ots]" file="tools/test_case_package.py" line="31" time="0.298"><failure message="assert ('Timestamp receipts (not verified)' in '&lt;!doctype html&gt;&lt;html lang=&quot;en&quot;&gt;&lt;meta charset=&quot;utf-8&quot;&gt;&lt;meta http-equiv=&quot;Content-Security-Policy&quot; content=&quot;default-src ...lank&quot;&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;Date: &lt;span class=&quot;blank&quot;&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;Place: &lt;span class=&quot;blank&quot;&gt;&lt;/span&gt;&lt;/p&gt;&lt;/div&gt;&lt;/body&gt;&lt;/html&gt;')">tmp_path = PosixPath('/tmp/pytest-of-root/pytest-6/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('&lt;section class="slide') &gt;= 5 and "Isolated browser capture" in slides and "explicit" not in slides
                payload = {"documentation.json", "report.html", "presentation.html", "verification.html", "indicators.csv",
                           "indicators.stix.json", "files/" + sha(PHOTO) + ".jpg", "files/" + sha(SCREEN) + ".png",
                           "timestamps/" + name + ".json", "timestamps/" + receipt_name,
                           "court/certification.html", "court/exhibits.html", "court/exhibits.csv", "court/request-annex.html",
                           "court/request-annex.csv", "court/request-annex.json", "court/undercover-record.html",
                           "court/undercover-record.json"}
                tags = {"bagit.txt", "bag-info.txt", "manifest-sha256.txt", "tagmanifest-sha256.txt", "README.txt"}
                assert names == {root + "data/" + p for p in payload} | {root + t for t in tags}
                certificate = archive.read(root + "data/court/certification.html").decode()
                for member in payload - {"court/certification.html"}:
                    digest = hashlib.sha256(archive.read(root + "data/" + member)).hexdigest()
                    assert digest in certificate and "data/" + member in certificate
                assert fixed["statement_sha256"] in certificate and "explicit" not in certificate
&gt;               assert "Timestamp receipts (not verified)" in certificate and "have not been verified" in certificate
E               assert ('Timestamp receipts (not verified)' in '&lt;!doctype html&gt;&lt;html lang="en"&gt;&lt;meta charset="utf-8"&gt;&lt;meta http-equiv="Content-Security-Policy" content="default-src ...lank"&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;Date: &lt;span class="blank"&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;Place: &lt;span class="blank"&gt;&lt;/span&gt;&lt;/p&gt;&lt;/div&gt;&lt;/body&gt;&lt;/html&gt;')

tools/test_case_package.py:82: AssertionError</failure></testcase><testcase classname="tools.test_case_package" name="test_kind_detection" file="tools/test_case_package.py" line="133" time="0.000" /><testcase classname="tools.test_case_package" name="test_missing_timestamp_receipts_are_explicitly_absent" file="tools/test_case_package.py" line="149" time="0.003" /><testcase classname="tools.test_channel_graph" name="test_depth_zero_records_the_seed_without_asking_telegram" file="tools/test_channel_graph.py" line="58" time="0.001" /><testcase classname="tools.test_channel_graph" name="test_second_level_is_only_walked_when_depth_allows_it" file="tools/test_channel_graph.py" line="65" time="0.001" /><testcase classname="tools.test_channel_graph" name="test_size_filters_drop_suggestions_but_keep_the_edge_and_the_count" file="tools/test_channel_graph.py" line="78" time="0.001" /><testcase classname="tools.test_channel_graph" name="test_username_and_restricted_filters" file="tools/test_channel_graph.py" line="90" time="0.001" /><testcase classname="tools.test_channel_graph" name="test_total_budget_stops_the_walk_and_is_reported" file="tools/test_channel_graph.py" line="100" time="0.001" /><testcase classname="tools.test_channel_graph" name="test_per_source_limits_what_one_channel_contributes" file="tools/test_channel_graph.py" line="107" time="0.001" /><testcase classname="tools.test_channel_graph" name="test_flood_wait_stops_the_walk_and_records_backoff" file="tools/test_channel_graph.py" line="113" time="0.001" /><testcase classname="tools.test_channel_graph" name="test_unreachable_source_is_recorded_and_the_walk_continues" file="tools/test_channel_graph.py" line="123" time="0.001" /><testcase classname="tools.test_channel_graph" name="test_a_cycle_is_visited_once" file="tools/test_channel_graph.py" line="131" time="0.001" /><testcase classname="tools.test_channel_graph" name="test_record_states_that_a_suggestion_is_not_a_relationship" file="tools/test_channel_graph.py" line="139" time="0.001" /><testcase classname="tools.test_channel_graph" name="test_unknown_size_is_kept_unless_a_size_filter_is_requested" file="tools/test_channel_graph.py" line="147" time="0.000" /><testcase classname="tools.test_channel_graph" name="test_options_reject_an_inverted_range" file="tools/test_channel_graph.py" line="153" time="0.000" /><testcase classname="tools.test_channel_graph" name="test_depth_and_total_have_bounds" file="tools/test_channel_graph.py" line="158" time="0.000" /><testcase classname="tools.test_chat_comparison" name="test_same_number_compares_every_saved_field[reply_to_message_id-20]" file="tools/test_chat_comparison.py" line="48" time="0.004" /><testcase classname="tools.test_chat_comparison" name="test_same_number_compares_every_saved_field[from_id-1002]" file="tools/test_chat_comparison.py" line="48" time="0.003" /><testcase classname="tools.test_chat_comparison" name="test_same_number_compares_every_saved_field[date-2026-11-05T20:00:00+00:00]" file="tools/test_chat_comparison.py" line="48" time="0.003" /><testcase classname="tools.test_chat_comparison" name="test_same_number_compares_every_saved_field[date_unixtime-1793908800]" file="tools/test_chat_comparison.py" line="48" time="0.003" /><testcase classname="tools.test_chat_comparison" name="test_same_number_compares_every_saved_field[text-No]" file="tools/test_chat_comparison.py" line="48" time="0.003" /><testcase classname="tools.test_chat_comparison" name="test_same_number_compares_every_saved_field[from-Different saved display name]" file="tools/test_chat_comparison.py" line="48" time="0.003" /><testcase classname="tools.test_chat_comparison" name="test_same_number_compares_every_saved_field[reply_to-value6]" file="tools/test_chat_comparison.py" line="48" time="0.003" /><testcase classname="tools.test_chat_comparison" name="test_same_number_compares_every_saved_field[text_entities-value7]" file="tools/test_chat_comparison.py" line="48" time="0.003" /><testcase classname="tools.test_chat_comparison" name="test_same_number_compares_every_saved_field[forwarded_from-value8]" file="tools/test_chat_comparison.py" line="48" time="0.003" /><testcase classname="tools.test_chat_comparison" name="test_same_number_compares_every_saved_field[future_field-value9]" file="tools/test_chat_comparison.py" line="48" time="0.003" /><testcase classname="tools.test_chat_comparison" name="test_text_after_preview_boundary_is_compared[False]" file="tools/test_chat_comparison.py" line="69" time="0.003" /><testcase classname="tools.test_chat_comparison" name="test_text_after_preview_boundary_is_compared[True]" file="tools/test_chat_comparison.py" line="69" time="0.003" /><testcase classname="tools.test_chat_comparison" name="test_identical_json_ignores_object_key_order" file="tools/test_chat_comparison.py" line="82" time="0.003" /><testcase classname="tools.test_chat_comparison" name="test_presence_json_type_and_array_order_matter[None-missing]" file="tools/test_chat_comparison.py" line="91" time="0.003" /><testcase classname="tools.test_chat_comparison" name="test_presence_json_type_and_array_order_matter[True-1]" file="tools/test_chat_comparison.py" line="91" time="0.003" /><testcase classname="tools.test_chat_comparison" name="test_presence_json_type_and_array_order_matter[first2-second2]" file="tools/test_chat_comparison.py" line="91" time="0.003" /><testcase classname="tools.test_chat_comparison" name="test_content_matching_uses_complete_text" file="tools/test_chat_comparison.py" line="101" time="0.003" /><testcase classname="tools.test_chat_comparison" name="test_content_correspondence_is_not_full_record_equality" file="tools/test_chat_comparison.py" line="109" time="0.003" /><testcase classname="tools.test_chat_comparison" name="test_missing_scope_identity_does_not_assert_number_match" file="tools/test_chat_comparison.py" line="120" time="0.003" /><testcase classname="tools.test_chat_comparison" name="test_duplicate_message_numbers_are_rejected" file="tools/test_chat_comparison.py" line="128" time="0.002" /><testcase classname="tools.test_chat_comparison" name="test_unparsed_records_are_not_silently_dropped[7]" file="tools/test_chat_comparison.py" line="135" time="0.003" /><testcase classname="tools.test_chat_comparison" name="test_unparsed_records_are_not_silently_dropped[8]" file="tools/test_chat_comparison.py" line="135" time="0.003" /><testcase classname="tools.test_chat_comparison" name="test_cli_names_metadata_difference_and_runs_standalone" file="tools/test_chat_comparison.py" line="148" time="0.130" /><testcase classname="tools.test_chat_comparison" name="test_signatures_and_pins_still_checked_before_comparison" file="tools/test_chat_comparison.py" line="158" time="0.007" /><testcase classname="tools.test_chat_export_integrity" name="test_recovered_attachments_and_profile_obey_export_choice[skip-skipped_by_export_option]" file="tools/test_chat_export_integrity.py" line="32" time="0.202" /><testcase classname="tools.test_chat_export_integrity" name="test_recovered_attachments_and_profile_obey_export_choice[hashes-hashes_only]" file="tools/test_chat_export_integrity.py" line="32" time="0.199" /><testcase classname="tools.test_chat_export_integrity" name="test_staged_files_cannot_replace_the_original_message[none]" file="tools/test_chat_export_integrity.py" line="69" time="0.168" /><testcase classname="tools.test_chat_export_integrity" name="test_staged_files_cannot_replace_the_original_message[text]" file="tools/test_chat_export_integrity.py" line="69" time="0.177" /><testcase classname="tools.test_chat_export_integrity" name="test_staged_files_cannot_replace_the_original_message[photo]" file="tools/test_chat_export_integrity.py" line="69" time="0.172" /><testcase classname="tools.test_chat_export_integrity" name="test_staged_files_cannot_replace_the_original_message[peer]" file="tools/test_chat_export_integrity.py" line="69" time="0.172" /><testcase classname="tools.test_chat_export_integrity" name="test_staged_files_cannot_replace_the_original_message[missing]" file="tools/test_chat_export_integrity.py" line="69" time="0.190" /><testcase classname="tools.test_chat_export_integrity" name="test_sparse_message_numbers_are_counted_without_expansion" file="tools/test_chat_export_integrity.py" line="95" time="0.001"><failure message="assert 2 == 1999999998&#10; +  where 2 = len((&lt;tgwitness.message_numbers.MissingNumbers object at 0x747f739f5670&gt;, 1))">tmp_path = PosixPath('/tmp/pytest-of-root/pytest-6/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)
&gt;       assert len(missing) == 1999999998
E       assert 2 == 1999999998
E        +  where 2 = len((&lt;tgwitness.message_numbers.MissingNumbers object at 0x747f739f5670&gt;, 1))

tools/test_chat_export_integrity.py:100: AssertionError</failure></testcase><testcase classname="tools.test_chat_export_integrity" name="test_multi_account_recovery_does_not_expand_missing_numbers" file="tools/test_chat_export_integrity.py" line="107" time="2.149" /><testcase classname="tools.test_chat_export_integrity" name="test_sparse_membership_uses_intervals" file="tools/test_chat_export_integrity.py" line="118" time="0.000" /><testcase classname="tools.test_chat_export_integrity" name="test_distributed_sparse_recheck_is_bounded_and_cancellable[False]" file="tools/test_chat_export_integrity.py" line="131" time="0.057" /><testcase classname="tools.test_chat_export_integrity" name="test_distributed_sparse_recheck_is_bounded_and_cancellable[True]" file="tools/test_chat_export_integrity.py" line="131" time="0.052" /><testcase classname="tools.test_chat_export_integrity" name="test_session_key_is_released_only_after_transport_shutdown[False]" file="tools/test_chat_export_integrity.py" line="173" time="0.180" /><testcase classname="tools.test_chat_export_integrity" name="test_session_key_is_released_only_after_transport_shutdown[True]" file="tools/test_chat_export_integrity.py" line="173" time="0.189" /><testcase classname="tools.test_chat_export_integrity" name="test_old_connection_cannot_unlock_a_different_session" file="tools/test_chat_export_integrity.py" line="217" time="0.192" /><testcase classname="tools.test_chat_export_integrity" name="test_new_login_key_is_reserved_after_connect" file="tools/test_chat_export_integrity.py" line="233" time="0.194" /><testcase classname="tools.test_chat_state" name="test_differences_name_what_changed_and_skip_unknown_parts" file="tools/test_chat_state.py" line="26" time="0.000" /><testcase classname="tools.test_chat_state" name="test_records_keep_full_states_and_compact_count_changes" file="tools/test_chat_state.py" line="47" time="0.227" /><testcase classname="tools.test_chat_state" name="test_compact_snapshots_reconstruct_all_counts_and_digest" file="tools/test_chat_state.py" line="68" time="0.224" /><testcase classname="tools.test_chat_state" name="test_unknown_scalars_are_not_cleared_but_explicit_null_is" file="tools/test_chat_state.py" line="80" time="0.217" /><testcase classname="tools.test_chat_state" name="test_partial_lists_do_not_claim_additions_or_removals" file="tools/test_chat_state.py" line="90" time="0.000" /><testcase classname="tools.test_chat_state" name="test_read_state_collects_parts_and_names_failures" file="tools/test_chat_state.py" line="135" time="0.001" /><testcase classname="tools.test_chat_state" name="test_fresh_identity_cleared_fields_and_list_limits" file="tools/test_chat_state.py" line="148" time="0.000" /><testcase classname="tools.test_chat_state" name="test_resume_after_disabled_parts_and_newly_available_counts" file="tools/test_chat_state.py" line="174" time="0.206" /><testcase classname="tools.test_chat_state" name="test_due_sources_are_snapshotted_and_floods_back_off" file="tools/test_chat_state.py" line="182" time="0.207" /><testcase classname="tools.test_chat_state" name="test_entity_lookup_flood_backs_off_instead_of_stopping_observation" file="tools/test_chat_state.py" line="211" time="0.203" /><testcase classname="tools.test_chat_state" name="test_all_floods_stop_parts_and_resume_without_losing_longer_wait[FloodWaitError]" file="tools/test_chat_state.py" line="226" time="0.240" /><testcase classname="tools.test_chat_state" name="test_all_floods_stop_parts_and_resume_without_losing_longer_wait[FloodPremiumWaitError]" file="tools/test_chat_state.py" line="226" time="0.224" /><testcase classname="tools.test_chat_state" name="test_snapshots_stay_in_verifiable_exports" file="tools/test_chat_state.py" line="256" time="0.908" /><testcase classname="tools.test_chat_timeline" name="test_daily_cells_rank_chats_and_count_the_rest" file="tools/test_chat_timeline.py" line="21" time="0.000" /><testcase classname="tools.test_chat_timeline" name="test_long_spans_use_weeks_then_months" file="tools/test_chat_timeline.py" line="33" time="0.000" /><testcase classname="tools.test_chat_timeline" name="test_columns_without_any_capture_are_marked" file="tools/test_chat_timeline.py" line="42" time="0.000" /><testcase classname="tools.test_chat_timeline" name="test_analytics_selection_carries_the_timeline_and_respects_the_chat_option" file="tools/test_chat_timeline.py" line="52" time="0.000" /><testcase classname="tools.test_chat_timeline" name="test_evidence_report_draws_chats_over_time" file="tools/test_chat_timeline.py" line="64" time="0.921" /><testcase classname="tools.test_chat_timeline" name="test_rows_carry_chat_titles_when_known" file="tools/test_chat_timeline.py" line="82" time="0.000" /><testcase classname="tools.test_checkpoint_drand_route" name="test_checkpoint_never_connects_out_and_carries_the_fetched_round" file="tools/test_checkpoint_drand_route.py" line="21" time="0.186" /><testcase classname="tools.test_checkpoint_drand_route" name="test_refresh_uses_the_outside_route_and_ignores_failures" file="tools/test_checkpoint_drand_route.py" line="38" time="0.203" /><testcase classname="tools.test_cli" name="test_activity_counts_saved_observations" file="tools/test_cli.py" line="78" time="0.295" /><testcase classname="tools.test_cli" name="test_activity_marks_unconfirmed_collection" file="tools/test_cli.py" line="108" time="0.340" /><testcase classname="tools.test_cli" name="test_local_commands" file="tools/test_cli.py" line="134" time="0.457"><failure message="AssertionError: assert [{'workspace'...n workspace'}] == [{'workspace'...ain account'}]&#10;  &#10;  At index 0 diff: {'workspace': 'default', 'name': 'Main workspace'} != {'workspace': 'default', 'name': 'Main account'}&#10;  Use -v to get more diff">workspace = PosixPath('/tmp/pytest-of-root/pytest-6/test_local_commands0')
capsys = &lt;_pytest.capture.CaptureFixture object at 0x747f726e09b0&gt;

    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)
&gt;       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</failure></testcase><testcase classname="tools.test_cli" name="test_exit_codes_and_clean_stdout" file="tools/test_cli.py" line="177" time="0.563" /><testcase classname="tools.test_cli" name="test_output_is_utf8_on_any_pipe" file="tools/test_cli.py" line="204" time="0.001" /><testcase classname="tools.test_cli" name="test_terminal_controls_are_removed_only_from_human_output" file="tools/test_cli.py" line="215" time="0.438" /><testcase classname="tools.test_cli" name="test_tool_lists" file="tools/test_cli.py" line="238" time="0.000" /><testcase classname="tools.test_cli" name="test_panel_mode_uses_scoped_connection" file="tools/test_cli.py" line="288" time="1.072" /><testcase classname="tools.test_cli" name="test_export_revocation_before_first_record_or_completion[False]" file="tools/test_cli.py" line="325" time="1.629" /><testcase classname="tools.test_cli" name="test_export_revocation_before_first_record_or_completion[True]" file="tools/test_cli.py" line="325" time="0.888" /><testcase classname="tools.test_cli" name="test_export_iteration_holds_archive_worker_budget" file="tools/test_cli.py" line="356" time="0.902" /><testcase classname="tools.test_client_checks" name="test_connection_checks_report_flags_without_safety_claims[True]" file="tools/test_client_checks.py" line="25" time="0.002" /><testcase classname="tools.test_client_checks" name="test_connection_checks_report_flags_without_safety_claims[False]" file="tools/test_client_checks.py" line="25" time="0.002" /><testcase classname="tools.test_client_checks" name="test_failed_checks_stop_and_do_not_report_false_flag[failure0]" file="tools/test_client_checks.py" line="38" time="0.001" /><testcase classname="tools.test_client_checks" name="test_failed_checks_stop_and_do_not_report_false_flag[failure1]" file="tools/test_client_checks.py" line="38" time="0.001" /><testcase classname="tools.test_client_checks" name="test_failed_checks_stop_and_do_not_report_false_flag[failure2]" file="tools/test_client_checks.py" line="38" time="0.001" /><testcase classname="tools.test_client_checks" name="test_checks_respect_saved_wait_and_share_concurrent_result" file="tools/test_client_checks.py" line="51" time="0.195" /><testcase classname="tools.test_client_checks" name="test_cancelled_or_replaced_client_cannot_leave_a_stale_check" file="tools/test_client_checks.py" line="74" time="0.188" /><testcase classname="tools.test_client_checks" name="test_reported_connection_keeps_actual_language_pack" file="tools/test_client_checks.py" line="104" time="0.190" /><testcase classname="tools.test_client_initialization" name="test_initialization_sequence[android-6]" file="tools/test_client_initialization.py" line="15" time="0.001" /><testcase classname="tools.test_client_initialization" name="test_initialization_sequence[tdesktop-6]" file="tools/test_client_initialization.py" line="15" time="0.001" /><testcase classname="tools.test_client_initialization" name="test_initialization_sequence[-5]" file="tools/test_client_initialization.py" line="15" time="0.001" /><testcase classname="tools.test_client_initialization" name="test_initialization_stops_without_retries_or_secret_errors[failure0]" file="tools/test_client_initialization.py" line="31" time="0.001" /><testcase classname="tools.test_client_initialization" name="test_initialization_stops_without_retries_or_secret_errors[failure1]" file="tools/test_client_initialization.py" line="31" time="0.001" /><testcase classname="tools.test_client_initialization" name="test_initialization_stops_without_retries_or_secret_errors[failure2]" file="tools/test_client_initialization.py" line="31" time="0.001" /><testcase classname="tools.test_client_initialization" name="test_initialization_only_on_new_authorization_and_signed" file="tools/test_client_initialization.py" line="43" time="0.280" /><testcase classname="tools.test_client_timezone" name="test_desktop_timezone[0-0]" file="tools/test_client_timezone.py" line="13" time="0.000" /><testcase classname="tools.test_client_timezone" name="test_desktop_timezone[450-900]" file="tools/test_client_timezone.py" line="13" time="0.001" /><testcase classname="tools.test_client_timezone" name="test_desktop_timezone[-450--900]" file="tools/test_client_timezone.py" line="13" time="0.001" /><testcase classname="tools.test_client_timezone" name="test_desktop_timezone[449-0]" file="tools/test_client_timezone.py" line="13" time="0.001" /><testcase classname="tools.test_client_timezone" name="test_desktop_timezone[-449-0]" file="tools/test_client_timezone.py" line="13" time="0.001" /><testcase classname="tools.test_client_timezone" name="test_desktop_timezone[20700-20700]" file="tools/test_client_timezone.py" line="13" time="0.001" /><testcase classname="tools.test_client_timezone" name="test_desktop_timezone[-36000--36000]" file="tools/test_client_timezone.py" line="13" time="0.001" /><testcase classname="tools.test_client_timezone" name="test_desktop_timezone[50400-50400]" file="tools/test_client_timezone.py" line="13" time="0.001" /><testcase classname="tools.test_client_timezone" name="test_desktop_timezone[54000--32400]" file="tools/test_client_timezone.py" line="13" time="0.001" /><testcase classname="tools.test_client_timezone" name="test_desktop_timezone[-46800-39600]" file="tools/test_client_timezone.py" line="13" time="0.001" /><testcase classname="tools.test_client_timezone" name="test_init_params_and_reconnect[tdesktop-supplied0--28800]" file="tools/test_client_timezone.py" line="20" time="0.002" /><testcase classname="tools.test_client_timezone" name="test_init_params_and_reconnect[tdesktop-supplied1-0]" file="tools/test_client_timezone.py" line="20" time="0.002" /><testcase classname="tools.test_client_timezone" name="test_init_params_and_reconnect[android-supplied2-None]" file="tools/test_client_timezone.py" line="20" time="0.002" /><testcase classname="tools.test_client_timezone" name="test_init_params_and_reconnect[android-supplied3--36001]" file="tools/test_client_timezone.py" line="20" time="0.002" /><testcase classname="tools.test_client_timezone" name="test_init_params_and_reconnect[-supplied4-None]" file="tools/test_client_timezone.py" line="20" time="0.002" /><testcase classname="tools.test_client_transport" name="test_transport_choices_and_route_switches" file="tools/test_client_transport.py" line="13" time="0.002" /><testcase classname="tools.test_client_transport" name="test_https_connect_initializes_real_obfuscation" file="tools/test_client_transport.py" line="36" time="0.002" /><testcase classname="tools.test_cloud_refactor" name="test_verification_cli_preserves_result_and_written_report[pass-0]" file="tools/test_cloud_refactor.py" line="8" time="0.007" /><testcase classname="tools.test_cloud_refactor" name="test_verification_cli_preserves_result_and_written_report[fail-1]" file="tools/test_cloud_refactor.py" line="8" time="0.003" /><testcase classname="tools.test_cloud_refactor" name="test_verification_cli_preserves_result_and_written_report[review-2]" file="tools/test_cloud_refactor.py" line="8" time="0.004" /><testcase classname="tools.test_cloud_refactor" name="test_verification_cli_preserves_result_and_written_report[incomplete-2]" file="tools/test_cloud_refactor.py" line="8" time="0.003" /><testcase classname="tools.test_cloud_refactor" name="test_verification_cli_preserves_result_and_written_report[self-attested-2]" file="tools/test_cloud_refactor.py" line="8" time="0.003" /><testcase classname="tools.test_cloud_refactor" name="test_verification_cli_reports_backend_errors_without_a_pass[error0]" file="tools/test_cloud_refactor.py" line="28" time="0.001" /><testcase classname="tools.test_cloud_refactor" name="test_verification_cli_reports_backend_errors_without_a_pass[error1]" file="tools/test_cloud_refactor.py" line="28" time="0.001" /><testcase classname="tools.test_conversation" name="test_templates_create_goals_and_plans_are_scoped_to_open_chats" file="tools/test_conversation.py" line="34" time="0.194" /><testcase classname="tools.test_conversation" name="test_goals_and_steps_can_be_edited_moved_and_removed" file="tools/test_conversation.py" line="49" time="0.256" /><testcase classname="tools.test_conversation" name="test_sent_steps_are_matched_passively_with_reply_times" file="tools/test_conversation.py" line="75" time="0.250" /><testcase classname="tools.test_conversation" name="test_edited_wording_panel_receipts_and_manual_links_are_recognised" file="tools/test_conversation.py" line="100" time="0.257" /><testcase classname="tools.test_conversation" name="test_a_stale_revision_is_refused_instead_of_overwriting" file="tools/test_conversation.py" line="126" time="0.202" /><testcase classname="tools.test_conversation" name="test_steps_written_before_the_message_do_not_match_older_messages" file="tools/test_conversation.py" line="140" time="0.205" /><testcase classname="tools.test_conversation" name="test_activity_uses_the_chosen_time_zone" file="tools/test_conversation.py" line="148" time="0.198" /><testcase classname="tools.test_conversation" name="test_observed_style_of_the_other_side" file="tools/test_conversation.py" line="156" time="0.263" /><testcase classname="tools.test_conversation" name="test_ai_preview_shows_exactly_what_is_sent_and_drafts_are_recorded" file="tools/test_conversation.py" line="183" time="0.282" /><testcase classname="tools.test_conversation" name="test_a_malformed_ai_answer_is_retried_once_with_a_reminder[first0]" file="tools/test_conversation.py" line="230" time="0.257" /><testcase classname="tools.test_conversation" name="test_a_malformed_ai_answer_is_retried_once_with_a_reminder[first1]" file="tools/test_conversation.py" line="230" time="0.252" /><testcase classname="tools.test_conversation" name="test_ai_answers_in_slightly_different_shapes_are_accepted[answer0-texts0]" file="tools/test_conversation.py" line="254" time="0.000" /><testcase classname="tools.test_conversation" name="test_ai_answers_in_slightly_different_shapes_are_accepted[answer1-texts1]" file="tools/test_conversation.py" line="254" time="0.000" /><testcase classname="tools.test_conversation" name="test_ai_answers_in_slightly_different_shapes_are_accepted[answer2-texts2]" file="tools/test_conversation.py" line="254" time="0.000" /><testcase classname="tools.test_conversation" name="test_ai_answers_in_slightly_different_shapes_are_accepted[answer3-texts3]" file="tools/test_conversation.py" line="254" time="0.000" /><testcase classname="tools.test_conversation" name="test_ai_context_is_trimmed_to_the_configured_size" file="tools/test_conversation.py" line="261" time="0.510" /><testcase classname="tools.test_conversation" name="test_ai_preview_needs_text_and_bad_answers_are_refused" file="tools/test_conversation.py" line="272" time="0.298" /><testcase classname="tools.test_conversation" name="test_plans_are_off_for_the_evidence_goal" file="tools/test_conversation.py" line="283" time="0.187" /><testcase classname="tools.test_conversation" name="test_api_routes_work_end_to_end_without_telegram" file="tools/test_conversation.py" line="290" time="0.752" /><testcase classname="tools.test_conversation" name="test_invalid_requests[Step-body0]" file="tools/test_conversation.py" line="323" time="0.001" /><testcase classname="tools.test_conversation" name="test_invalid_requests[Step-body1]" file="tools/test_conversation.py" line="323" time="0.000" /><testcase classname="tools.test_conversation" name="test_invalid_requests[Step-body2]" file="tools/test_conversation.py" line="323" time="0.000" /><testcase classname="tools.test_conversation" name="test_invalid_requests[Goal-body3]" file="tools/test_conversation.py" line="323" time="0.000" /><testcase classname="tools.test_conversation" name="test_invalid_requests[Goal-body4]" file="tools/test_conversation.py" line="323" time="0.000" /><testcase classname="tools.test_conversation" name="test_invalid_requests[Goal-body5]" file="tools/test_conversation.py" line="323" time="0.000" /><testcase classname="tools.test_conversation" name="test_invalid_requests[Assist-body6]" file="tools/test_conversation.py" line="323" time="0.000" /><testcase classname="tools.test_conversation" name="test_invalid_requests[Assist-body7]" file="tools/test_conversation.py" line="323" time="0.000" /><testcase classname="tools.test_conversation" name="test_invalid_requests[Edit-body8]" file="tools/test_conversation.py" line="323" time="0.000" /><testcase classname="tools.test_conversation" name="test_invalid_requests[Create-body9]" file="tools/test_conversation.py" line="323" time="0.000" /><testcase classname="tools.test_court" name="test_message_links_follow_telegram_rules" file="tools/test_court.py" line="28" time="0.000" /><testcase classname="tools.test_court" name="test_annex_lists_ids_usernames_labels_and_skips_hidden_steps" file="tools/test_court.py" line="35" time="0.000" /><testcase classname="tools.test_court" name="test_exhibits_are_numbered_once_per_file_and_hidden_files_are_left_out" file="tools/test_court.py" line="49" time="0.000" /><testcase classname="tools.test_crypto_ids" name="test_official_eip55_vectors[0x5aAeb6053F3E94C9b9A09f33669435E7Ef1BeAed]" file="tools/test_crypto_ids.py" line="25" time="0.001" /><testcase classname="tools.test_crypto_ids" name="test_official_eip55_vectors[0xfB6916095ca1df60bB79Ce92cE3Ea74c37c5d359]" file="tools/test_crypto_ids.py" line="25" time="0.001" /><testcase classname="tools.test_crypto_ids" name="test_official_eip55_vectors[0xdbF03B407c01E7cD3CBea99509d93f8DDDC8C6FB]" file="tools/test_crypto_ids.py" line="25" time="0.001" /><testcase classname="tools.test_crypto_ids" name="test_official_eip55_vectors[0xD1220A0cf47c7B9Be7A2E6BA89F429762e7b9aDb]" file="tools/test_crypto_ids.py" line="25" time="0.001" /><testcase classname="tools.test_crypto_ids" name="test_keccak256_matches_the_published_digests" file="tools/test_crypto_ids.py" line="31" time="0.001" /><testcase classname="tools.test_crypto_ids" name="test_an_address_with_a_broken_checksum_is_not_reported_as_a_wallet" file="tools/test_crypto_ids.py" line="36" time="0.001" /><testcase classname="tools.test_crypto_ids" name="test_every_spelling_of_one_ton_account_normalises_to_the_same_raw_form" file="tools/test_crypto_ids.py" line="46" time="0.000" /><testcase classname="tools.test_crypto_ids" name="test_xrp_addresses_are_checked_and_carry_the_destination_tag_warning" file="tools/test_crypto_ids.py" line="55" time="0.000" /><testcase classname="tools.test_crypto_ids" name="test_transaction_hashes_need_the_chain_or_the_context" file="tools/test_crypto_ids.py" line="62" time="0.000" /><testcase classname="tools.test_crypto_ids" name="test_payment_links_give_the_recipient_not_the_token_contract" file="tools/test_crypto_ids.py" line="72" time="0.001" /><testcase classname="tools.test_crypto_ids" name="test_the_indicator_export_keeps_the_new_kinds" file="tools/test_crypto_ids.py" line="85" time="0.001" /><testcase classname="tools.test_deletion_evidence_reports" name="test_signed_json_counts_only_received_deletion_notices[False]" file="tools/test_deletion_evidence_reports.py" line="38" time="0.198" /><testcase classname="tools.test_deletion_evidence_reports" name="test_signed_json_counts_only_received_deletion_notices[True]" file="tools/test_deletion_evidence_reports.py" line="38" time="0.204" /><testcase classname="tools.test_deletion_evidence_reports" name="test_html_viewer_distinguishes_missing_from_deleted" file="tools/test_deletion_evidence_reports.py" line="51" time="0.213" /><testcase classname="tools.test_deletion_evidence_reports" name="test_reappearance_does_not_turn_past_absence_into_a_deletion" file="tools/test_deletion_evidence_reports.py" line="66" time="0.224" /><testcase classname="tools.test_deletion_evidence_reports" name="test_unscoped_notice_does_not_claim_that_a_known_disabled_chat_was_never_saved" file="tools/test_deletion_evidence_reports.py" line="78" time="0.225" /><testcase classname="tools.test_deletion_semantics" name="test_deletion_of_subset_keeps_actor_and_whole_history_unknown[2-55123]" file="tools/test_deletion_semantics.py" line="15" time="0.253"><failure message="AssertionError: assert 'does not identify who deleted them' in 'Telegram reported several message IDs as deleted in one update.'">tmp_path = PosixPath('/tmp/pytest-of-root/pytest-6/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 &gt; 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 &gt; 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 &gt; 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()
&gt;       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 &gt; 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 &gt; 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 &gt; 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"]
&gt;           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</failure></testcase><testcase classname="tools.test_deletion_semantics" name="test_deletion_of_subset_keeps_actor_and_whole_history_unknown[2--1000000000555]" file="tools/test_deletion_semantics.py" line="15" time="0.251"><failure message="AssertionError: assert 'does not identify who deleted them' in 'Telegram reported several message IDs as deleted in one update.'">tmp_path = PosixPath('/tmp/pytest-of-root/pytest-6/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 &gt; 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 &gt; 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 &gt; 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()
&gt;       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 &gt; 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 &gt; 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 &gt; 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"]
&gt;           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</failure></testcase><testcase classname="tools.test_deletion_semantics" name="test_deletion_of_subset_keeps_actor_and_whole_history_unknown[9-55123]" file="tools/test_deletion_semantics.py" line="15" time="0.414"><failure message="AssertionError: assert 'does not identify who deleted them' in 'Telegram reported several message IDs as deleted in one update.'">tmp_path = PosixPath('/tmp/pytest-of-root/pytest-6/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 &gt; 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 &gt; 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 &gt; 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()
&gt;       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 &gt; 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 &gt; 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 &gt; 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"]
&gt;           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</failure></testcase><testcase classname="tools.test_deletion_semantics" name="test_deletion_of_subset_keeps_actor_and_whole_history_unknown[9--1000000000555]" file="tools/test_deletion_semantics.py" line="15" time="0.286"><failure message="AssertionError: assert 'does not identify who deleted them' in 'Telegram reported several message IDs as deleted in one update.'">tmp_path = PosixPath('/tmp/pytest-of-root/pytest-6/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 &gt; 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 &gt; 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 &gt; 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()
&gt;       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 &gt; 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 &gt; 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 &gt; 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"]
&gt;           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</failure></testcase><testcase classname="tools.test_deletion_semantics" name="test_deletion_of_subset_keeps_actor_and_whole_history_unknown[10-55123]" file="tools/test_deletion_semantics.py" line="15" time="0.270"><failure message="AssertionError: assert 'does not identify who deleted them' in 'Telegram reported several message IDs as deleted in one update.'">tmp_path = PosixPath('/tmp/pytest-of-root/pytest-6/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 &gt; 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 &gt; 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 &gt; 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()
&gt;       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 &gt; 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 &gt; 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 &gt; 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"]
&gt;           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</failure></testcase><testcase classname="tools.test_deletion_semantics" name="test_deletion_of_subset_keeps_actor_and_whole_history_unknown[10--1000000000555]" file="tools/test_deletion_semantics.py" line="15" time="0.270"><failure message="AssertionError: assert 'does not identify who deleted them' in 'Telegram reported several message IDs as deleted in one update.'">tmp_path = PosixPath('/tmp/pytest-of-root/pytest-6/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 &gt; 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 &gt; 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 &gt; 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()
&gt;       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 &gt; 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 &gt; 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 &gt; 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"]
&gt;           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</failure></testcase><testcase classname="tools.test_deletion_semantics" name="test_deletion_of_subset_keeps_actor_and_whole_history_unknown[15-55123]" file="tools/test_deletion_semantics.py" line="15" time="0.300"><failure message="AssertionError: assert 'does not identify who deleted them' in 'Telegram reported several message IDs as deleted in one update.'">tmp_path = PosixPath('/tmp/pytest-of-root/pytest-6/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 &gt; 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 &gt; 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 &gt; 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()
&gt;       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 &gt; 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 &gt; 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 &gt; 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"]
&gt;           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</failure></testcase><testcase classname="tools.test_deletion_semantics" name="test_deletion_of_subset_keeps_actor_and_whole_history_unknown[15--1000000000555]" file="tools/test_deletion_semantics.py" line="15" time="0.314"><failure message="AssertionError: assert 'does not identify who deleted them' in 'Telegram reported several message IDs as deleted in one update.'">tmp_path = PosixPath('/tmp/pytest-of-root/pytest-6/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 &gt; 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 &gt; 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 &gt; 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()
&gt;       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 &gt; 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 &gt; 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 &gt; 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"]
&gt;           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</failure></testcase><testcase classname="tools.test_device_attribution" name="test_round_video_points_at_a_client[raw0-Telegram Desktop-weak]" file="tools/test_device_attribution.py" line="29" time="0.000" /><testcase classname="tools.test_device_attribution" name="test_round_video_points_at_a_client[raw1-Telegram for Android-weak]" file="tools/test_device_attribution.py" line="29" time="0.000" /><testcase classname="tools.test_device_attribution" name="test_round_video_points_at_a_client[raw2-Telegram for macOS-weak]" file="tools/test_device_attribution.py" line="29" time="0.000" /><testcase classname="tools.test_device_attribution" name="test_round_video_points_at_a_client[raw3-Telegram X-weak]" file="tools/test_device_attribution.py" line="29" time="0.000" /><testcase classname="tools.test_device_attribution" name="test_round_video_points_at_a_client[raw4-Telegram for iOS or Telegram Web-weak]" file="tools/test_device_attribution.py" line="29" time="0.000" /><testcase classname="tools.test_device_attribution" name="test_a_plain_video_says_nothing_about_the_client" file="tools/test_device_attribution.py" line="42" time="0.000" /><testcase classname="tools.test_device_attribution" name="test_voice_encoder_points_at_a_client[libopus 1.5.1-Telegram for iOS]" file="tools/test_device_attribution.py" line="48" time="0.000" /><testcase classname="tools.test_device_attribution" name="test_voice_encoder_points_at_a_client[libopus unknown-fixed-Telegram for Android]" file="tools/test_device_attribution.py" line="48" time="0.000" /><testcase classname="tools.test_device_attribution" name="test_voice_encoder_points_at_a_client[libopus 1.3.1-fixed-Telegram for macOS]" file="tools/test_device_attribution.py" line="48" time="0.000" /><testcase classname="tools.test_device_attribution" name="test_voice_encoder_points_at_a_client[Lavf61.7.100-Telegram Desktop]" file="tools/test_device_attribution.py" line="48" time="0.000" /><testcase classname="tools.test_device_attribution" name="test_voice_encoder_points_at_a_client[tweb-Telegram Web K]" file="tools/test_device_attribution.py" line="48" time="0.000" /><testcase classname="tools.test_device_attribution" name="test_voice_encoder_points_at_a_client[telegram-web-a-Telegram Web A]" file="tools/test_device_attribution.py" line="48" time="0.000" /><testcase classname="tools.test_device_attribution" name="test_an_unknown_or_broken_encoder_is_reported_honestly" file="tools/test_device_attribution.py" line="58" time="0.000" /><testcase classname="tools.test_device_attribution" name="test_media_uploaded_before_the_message_is_flagged_with_the_gap" file="tools/test_device_attribution.py" line="66" time="0.000" /><testcase classname="tools.test_device_attribution" name="test_sticker_sets_are_collected_without_inventing_an_owner" file="tools/test_device_attribution.py" line="77" time="0.000" /><testcase classname="tools.test_device_attribution" name="test_the_dossier_counts_clients_sticker_sets_and_prepared_media" file="tools/test_device_attribution.py" line="89" time="0.225"><failure message="assert 'Metadata hypothesis about the client that encoded the file' in &quot;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.&quot;">tmp_path = PosixPath('/tmp/pytest-of-root/pytest-6/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"}
&gt;           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</failure></testcase><testcase classname="tools.test_device_attribution" name="test_telegram_hints_about_the_other_side_are_recorded_and_explained" file="tools/test_device_attribution.py" line="112" time="0.000" /><testcase classname="tools.test_device_attribution" name="test_the_collector_records_peer_settings_with_flags_and_facts" file="tools/test_device_attribution.py" line="134" time="0.199" /><testcase classname="tools.test_device_attribution" name="test_voice_header_requires_the_complete_file_to_match_its_recorded_digest" file="tools/test_device_attribution.py" line="173" time="0.204" /><testcase classname="tools.test_device_attribution" name="test_voice_files_reject_path_like_or_noncanonical_digests[../outside.ogg]" file="tools/test_device_attribution.py" line="185" time="0.246" /><testcase classname="tools.test_device_attribution" name="test_voice_files_reject_path_like_or_noncanonical_digests[../../outside.ogg]" file="tools/test_device_attribution.py" line="185" time="0.224" /><testcase classname="tools.test_device_attribution" name="test_voice_files_reject_path_like_or_noncanonical_digests[..\\outside.ogg]" file="tools/test_device_attribution.py" line="185" time="0.216" /><testcase classname="tools.test_device_attribution" name="test_voice_files_reject_path_like_or_noncanonical_digests[AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA]" file="tools/test_device_attribution.py" line="185" time="0.217" /><testcase classname="tools.test_device_attribution" name="test_voice_files_reject_path_like_or_noncanonical_digests[000000000000000000000000000000000000000000000000000000000000000]" file="tools/test_device_attribution.py" line="185" time="0.221" /><testcase classname="tools.test_device_attribution" name="test_voice_files_reject_absolute_paths" file="tools/test_device_attribution.py" line="193" time="0.215" /><testcase classname="tools.test_device_attribution" name="test_voice_files_reject_symlinked_media_and_directories[False]" file="tools/test_device_attribution.py" line="200" time="0.221" /><testcase classname="tools.test_device_attribution" name="test_voice_files_reject_symlinked_media_and_directories[True]" file="tools/test_device_attribution.py" line="200" time="0.219" /><testcase classname="tools.test_device_attribution" name="test_voice_hashing_has_a_total_read_budget" file="tools/test_device_attribution.py" line="221" time="0.212" /><testcase classname="tools.test_difference_gaps" name="test_channel_difference_too_long_is_reported_with_both_positions" file="tools/test_difference_gaps.py" line="24" time="0.001" /><testcase classname="tools.test_difference_gaps" name="test_recovered_channel_difference_is_not_a_gap" file="tools/test_difference_gaps.py" line="38" time="0.000" /><testcase classname="tools.test_difference_gaps" name="test_account_difference_too_long_is_reported" file="tools/test_difference_gaps.py" line="50" time="0.000" /><testcase classname="tools.test_difference_gaps" name="test_listener_failure_does_not_break_update_processing" file="tools/test_difference_gaps.py" line="60" time="0.001" /><testcase classname="tools.test_difference_gaps" name="test_collector_records_only_selected_channels_as_incomplete_coverage" file="tools/test_difference_gaps.py" line="71" time="0.000" /><testcase classname="tools.test_disclosure_markers" name="test_markers_keep_the_shape_of_the_chat" file="tools/test_disclosure_markers.py" line="45" time="0.001" /><testcase classname="tools.test_disclosure_markers" name="test_pseudonymized_replies_point_at_their_markers" file="tools/test_disclosure_markers.py" line="61" time="0.001" /><testcase classname="tools.test_disclosure_markers" name="test_disclosure_package_is_marked_and_verified" file="tools/test_disclosure_markers.py" line="134" time="1.009" /><testcase classname="tools.test_disclosure_markers" name="test_marker_payload_cannot_carry_withheld_content[text-private message content]" file="tools/test_disclosure_markers.py" line="180" time="0.950" /><testcase classname="tools.test_disclosure_markers" name="test_marker_payload_cannot_carry_withheld_content[redacted_fields-value1]" file="tools/test_disclosure_markers.py" line="180" time="0.947" /><testcase classname="tools.test_disclosure_markers" name="test_marker_payload_cannot_carry_withheld_content[rules-value2]" file="tools/test_disclosure_markers.py" line="180" time="0.939" /><testcase classname="tools.test_disclosure_markers" name="test_reply_cannot_label_an_existing_record_as_absent" file="tools/test_disclosure_markers.py" line="197" time="0.897" /><testcase classname="tools.test_distributed_export" name="test_monitoring_rejects_all_export_claims_without_stopping" file="tools/test_distributed_export.py" line="43" time="0.209" /><testcase classname="tools.test_distributed_export" name="test_start_race_reserves_monitoring_before_first_await" file="tools/test_distributed_export.py" line="66" time="0.218" /><testcase classname="tools.test_distributed_export" name="test_rpc_calls_and_batch_are_serial" file="tools/test_distributed_export.py" line="95" time="0.004" /><testcase classname="tools.test_distributed_export" name="test_floodwait_is_full_and_persisted_before_next_rpc[FloodWaitError]" file="tools/test_distributed_export.py" line="113" time="0.003" /><testcase classname="tools.test_distributed_export" name="test_floodwait_is_full_and_persisted_before_next_rpc[FloodPremiumWaitError]" file="tools/test_distributed_export.py" line="113" time="0.003" /><testcase classname="tools.test_distributed_export" name="test_reconnect_does_not_shorten_persisted_flood_wait" file="tools/test_distributed_export.py" line="137" time="0.227" /><testcase classname="tools.test_distributed_export" name="test_export_retry_waits_without_changing_api_pair[FloodWaitError]" file="tools/test_distributed_export.py" line="157" time="0.001" /><testcase classname="tools.test_distributed_export" name="test_export_retry_waits_without_changing_api_pair[FloodPremiumWaitError]" file="tools/test_distributed_export.py" line="157" time="0.001" /><testcase classname="tools.test_distributed_export" name="test_cross_language_reply_and_outside_period_context" file="tools/test_distributed_export.py" line="177" time="0.072" /><testcase classname="tools.test_distributed_export" name="test_answer_scope_and_forum_topic_are_not_conflated" file="tools/test_distributed_export.py" line="198" time="0.080" /><testcase classname="tools.test_distributed_export" name="test_language_detection_keeps_short_text_unknown" file="tools/test_distributed_export.py" line="219" time="0.044" /><testcase classname="tools.test_distributed_export" name="test_undecodable_message_is_recorded_and_history_continues" file="tools/test_distributed_export.py" line="292" time="0.212" /><testcase classname="tools.test_distributed_export" name="test_undecodable_newest_message_does_not_block_the_start" file="tools/test_distributed_export.py" line="316" time="1.960" /><testcase classname="tools.test_distributed_export" name="test_distributed_profile_photo_respects_export_and_capture_settings[False-True-True-False]" file="tools/test_distributed_export.py" line="364" time="0.509" /><testcase classname="tools.test_distributed_export" name="test_distributed_profile_photo_respects_export_and_capture_settings[True-False-True-False]" file="tools/test_distributed_export.py" line="364" time="0.487" /><testcase classname="tools.test_distributed_export" name="test_distributed_profile_photo_respects_export_and_capture_settings[True-True-False-False]" file="tools/test_distributed_export.py" line="364" time="0.498" /><testcase classname="tools.test_distributed_export" name="test_distributed_profile_photo_respects_export_and_capture_settings[True-True-True-True]" file="tools/test_distributed_export.py" line="364" time="0.516" /><testcase classname="tools.test_distributed_export" name="test_export_rate_includes_waits_but_excludes_reused_messages_and_packaging[done]" file="tools/test_distributed_export.py" line="389" time="0.001" /><testcase classname="tools.test_distributed_export" name="test_export_rate_includes_waits_but_excludes_reused_messages_and_packaging[paused]" file="tools/test_distributed_export.py" line="389" time="0.000" /><testcase classname="tools.test_distributed_export" name="test_export_rate_includes_waits_but_excludes_reused_messages_and_packaging[failed]" file="tools/test_distributed_export.py" line="389" time="0.000" /><testcase classname="tools.test_distributed_export" name="test_multi_start_is_atomic_when_one_account_monitors" file="tools/test_distributed_export.py" line="441" time="0.491" /><testcase classname="tools.test_distributed_export" name="test_resume_reuses_signed_chunks_and_rejects_tampering" file="tools/test_distributed_export.py" line="457" time="0.957" /><testcase classname="tools.test_distributed_export" name="test_failed_archive_verification_keeps_selection_and_media" file="tools/test_distributed_export.py" line="502" time="1.928" /><testcase classname="tools.test_distributed_export" name="test_link_export_resolves_username_and_retains_collectible_name" file="tools/test_distributed_export.py" line="524" time="0.297" /><testcase classname="tools.test_distributed_export" name="test_post_verification_failure_retains_archive_and_recovery_files[outbox]" file="tools/test_distributed_export.py" line="544" time="1.130" /><testcase classname="tools.test_distributed_export" name="test_post_verification_failure_retains_archive_and_recovery_files[completion_journal]" file="tools/test_distributed_export.py" line="544" time="1.136" /><testcase classname="tools.test_distributed_export" name="test_filtered_archive_is_verifiable_and_contains_context" file="tools/test_distributed_export.py" line="584" time="1.525" /><testcase classname="tools.test_distributed_export" name="test_date_selection_keeps_every_message_at_inclusive_start[0-False]" file="tools/test_distributed_export.py" line="625" time="0.493" /><testcase classname="tools.test_distributed_export" name="test_date_selection_keeps_every_message_at_inclusive_start[0-True]" file="tools/test_distributed_export.py" line="625" time="0.513" /><testcase classname="tools.test_distributed_export" name="test_date_selection_keeps_every_message_at_inclusive_start[500000-False]" file="tools/test_distributed_export.py" line="625" time="0.494" /><testcase classname="tools.test_distributed_export" name="test_date_selection_keeps_every_message_at_inclusive_start[500000-True]" file="tools/test_distributed_export.py" line="625" time="0.468" /><testcase classname="tools.test_distributed_export" name="test_cancelling_an_old_job_leaves_the_active_one_running" file="tools/test_distributed_export.py" line="666" time="0.315" /><testcase classname="tools.test_distributed_export" name="test_preflight_cancellation_releases_every_account" file="tools/test_distributed_export.py" line="688" time="0.407" /><testcase classname="tools.test_distributed_export" name="test_workers_finish_cleanup_before_accounts_are_released[failure]" file="tools/test_distributed_export.py" line="715" time="0.496" /><testcase classname="tools.test_distributed_export" name="test_workers_finish_cleanup_before_accounts_are_released[pause]" file="tools/test_distributed_export.py" line="715" time="0.483" /><testcase classname="tools.test_distributed_export" name="test_workers_finish_cleanup_before_accounts_are_released[repeated_pause]" file="tools/test_distributed_export.py" line="715" time="0.468" /><testcase classname="tools.test_distributed_export" name="test_workers_finish_cleanup_before_accounts_are_released[failure_then_pause]" file="tools/test_distributed_export.py" line="715" time="0.541" /><testcase classname="tools.test_distributed_export" name="test_context_cap_and_precise_half_open_dates" file="tools/test_distributed_export.py" line="772" time="0.103" /><testcase classname="tools.test_distributed_export" name="test_rpc_peer_resolution_reentrancy_and_cancelled_wait" file="tools/test_distributed_export.py" line="792" time="0.011" /><testcase classname="tools.test_distributed_export" name="test_unfiltered_archive_keeps_number_analysis_and_rechecks_gaps" file="tools/test_distributed_export.py" line="813" time="2.658" /><testcase classname="tools.test_distributed_export" name="test_recheck_reads_below_the_oldest_listed_message_and_counts_unchecked" file="tools/test_distributed_export.py" line="840" time="1.806" /><testcase classname="tools.test_distributed_export" name="test_silent_account_returns_its_range_and_comes_back" file="tools/test_distributed_export.py" line="891" time="7.059" /><testcase classname="tools.test_distributed_export" name="test_range_failing_on_two_accounts_stops_without_losing_accounts" file="tools/test_distributed_export.py" line="913" time="1.260" /><testcase classname="tools.test_distributed_export" name="test_export_names_deletions_kept_in_the_journal" file="tools/test_distributed_export.py" line="932" time="1.607" /><testcase classname="tools.test_distributed_export" name="test_compare_finds_removed_and_edited_messages" file="tools/test_distributed_export.py" line="955" time="4.937" /><testcase classname="tools.test_distributed_export" name="test_full_recheck_reads_every_absent_number" file="tools/test_distributed_export.py" line="987" time="1.676" /><testcase classname="tools.test_distributed_export" name="test_ranges_are_read_through_a_takeout_session" file="tools/test_distributed_export.py" line="1029" time="1.494" /><testcase classname="tools.test_distributed_export" name="test_ten_accounts_cover_chunks_once" file="tools/test_distributed_export.py" line="1055" time="2.856" /><testcase classname="tools.test_distributed_pages" name="test_restart_reuses_a_signed_page_inside_the_same_chunk" file="tools/test_distributed_pages.py" line="36" time="0.613" /><testcase classname="tools.test_distributed_pages" name="test_crash_tail_never_advances_the_saved_cursor[unsigned_tail]" file="tools/test_distributed_pages.py" line="69" time="0.630" /><testcase classname="tools.test_distributed_pages" name="test_crash_tail_never_advances_the_saved_cursor[receipt_write]" file="tools/test_distributed_pages.py" line="69" time="0.716" /><testcase classname="tools.test_distributed_pages" name="test_crash_tail_never_advances_the_saved_cursor[disk_full]" file="tools/test_distributed_pages.py" line="69" time="0.702" /><testcase classname="tools.test_distributed_pages" name="test_crash_tail_never_advances_the_saved_cursor[process_exit]" file="tools/test_distributed_pages.py" line="69" time="0.560" /><testcase classname="tools.test_distributed_pages" name="test_damaged_checkpoint_stops_before_any_telegram_request[data]" file="tools/test_distributed_pages.py" line="125" time="0.407" /><testcase classname="tools.test_distributed_pages" name="test_damaged_checkpoint_stops_before_any_telegram_request[signature]" file="tools/test_distributed_pages.py" line="125" time="0.390" /><testcase classname="tools.test_distributed_pages" name="test_damaged_checkpoint_stops_before_any_telegram_request[plan]" file="tools/test_distributed_pages.py" line="125" time="0.404" /><testcase classname="tools.test_distributed_pages" name="test_damaged_checkpoint_stops_before_any_telegram_request[cursor]" file="tools/test_distributed_pages.py" line="125" time="0.418" /><testcase classname="tools.test_distributed_pages" name="test_damaged_checkpoint_stops_before_any_telegram_request[chain]" file="tools/test_distributed_pages.py" line="125" time="0.416" /><testcase classname="tools.test_distributed_pages" name="test_damaged_checkpoint_stops_before_any_telegram_request[observer]" file="tools/test_distributed_pages.py" line="125" time="0.465" /><testcase classname="tools.test_distributed_pages" name="test_damaged_checkpoint_stops_before_any_telegram_request[generation]" file="tools/test_distributed_pages.py" line="125" time="0.433" /><testcase classname="tools.test_distributed_pages" name="test_damaged_checkpoint_stops_before_any_telegram_request[missing_page]" file="tools/test_distributed_pages.py" line="125" time="0.449" /><testcase classname="tools.test_distributed_pages" name="test_pause_drains_inflight_checkpoint_before_releasing_account" file="tools/test_distributed_pages.py" line="159" time="0.657" /><testcase classname="tools.test_distributed_pages" name="test_partial_range_cannot_move_to_another_account" file="tools/test_distributed_pages.py" line="195" time="0.575" /><testcase classname="tools.test_distributed_pages" name="test_old_chunk_plan_still_resumes_without_page_migration" file="tools/test_distributed_pages.py" line="223" time="0.529" /><testcase classname="tools.test_distributed_pages" name="test_standalone_verifier_checks_paused_prefix_without_vault_or_database" file="tools/test_distributed_pages.py" line="251" time="0.715" /><testcase classname="tools.test_distributed_pages" name="test_empty_and_full_checkpoints_preserve_terminal_state[0]" file="tools/test_distributed_pages.py" line="275" time="0.415" /><testcase classname="tools.test_distributed_pages" name="test_empty_and_full_checkpoints_preserve_terminal_state[100]" file="tools/test_distributed_pages.py" line="275" time="0.517" /><testcase classname="tools.test_distributed_pages" name="test_empty_and_full_checkpoints_preserve_terminal_state[200]" file="tools/test_distributed_pages.py" line="275" time="0.570" /><testcase classname="tools.test_distributed_pages" name="test_empty_and_full_checkpoints_preserve_terminal_state[201]" file="tools/test_distributed_pages.py" line="275" time="0.549" /><testcase classname="tools.test_distributed_pages" name="test_checkpoint_prefix_survives_a_full_flood_wait" file="tools/test_distributed_pages.py" line="304" time="0.557" /><testcase classname="tools.test_distributed_pages" name="test_new_takeout_generation_does_not_rewrite_committed_pages" file="tools/test_distributed_pages.py" line="333" time="0.706" /><testcase classname="tools.test_distributed_pages" name="test_bad_iterator_records_cannot_seal_a_range[duplicate]" file="tools/test_distributed_pages.py" line="358" time="0.381" /><testcase classname="tools.test_distributed_pages" name="test_bad_iterator_records_cannot_seal_a_range[wrong_source]" file="tools/test_distributed_pages.py" line="358" time="0.357" /><testcase classname="tools.test_distributed_pages" name="test_bad_iterator_records_cannot_seal_a_range[outside_range]" file="tools/test_distributed_pages.py" line="358" time="0.377" /><testcase classname="tools.test_distributed_pages" name="test_chunk_footer_cannot_claim_a_different_takeout_generation" file="tools/test_distributed_pages.py" line="384" time="0.507" /><testcase classname="tools.test_distributed_takeout" name="test_takeout_private_lifecycle_reuse_and_range_validation" file="tools/test_distributed_takeout.py" line="93" time="0.295" /><testcase classname="tools.test_distributed_takeout" name="test_invalid_takeout_requires_explicit_retry_and_account_binding" file="tools/test_distributed_takeout.py" line="122" time="0.301" /><testcase classname="tools.test_distributed_takeout" name="test_takeout_delay_pauses_without_regular_fallback" file="tools/test_distributed_takeout.py" line="147" time="0.331" /><testcase classname="tools.test_distributed_takeout" name="test_real_telethon_iterator_removes_only_takeout_sleep" file="tools/test_distributed_takeout.py" line="167" time="0.258" /><testcase classname="tools.test_distributed_takeout" name="test_sparse_plan_reduces_requests_without_omitting_ids[regular]" file="tools/test_distributed_takeout.py" line="200" time="0.786" /><testcase classname="tools.test_distributed_takeout" name="test_sparse_plan_reduces_requests_without_omitting_ids[takeout]" file="tools/test_distributed_takeout.py" line="200" time="0.830" /><testcase classname="tools.test_distributed_takeout" name="test_takeout_archive_keeps_signatures_and_private_handles" file="tools/test_distributed_takeout.py" line="243" time="1.695" /><testcase classname="tools.test_distributed_takeout" name="test_takeout_pause_resume_reuses_signed_chunks_and_handle" file="tools/test_distributed_takeout.py" line="271" time="1.019" /><testcase classname="tools.test_distributed_takeout" name="test_takeout_rejects_unsupported_source_or_transport[False]" file="tools/test_distributed_takeout.py" line="304" time="0.269" /><testcase classname="tools.test_distributed_takeout" name="test_takeout_rejects_unsupported_source_or_transport[True]" file="tools/test_distributed_takeout.py" line="304" time="0.279" /><testcase classname="tools.test_distributed_takeout" name="test_takeout_flood_resume_keeps_cursor_and_transport[FloodWaitError]" file="tools/test_distributed_takeout.py" line="321" time="0.329" /><testcase classname="tools.test_distributed_takeout" name="test_takeout_flood_resume_keeps_cursor_and_transport[FloodPremiumWaitError]" file="tools/test_distributed_takeout.py" line="321" time="0.337" /><testcase classname="tools.test_distributed_takeout" name="test_pending_rate_limit_rejects_export_before_any_preflight" file="tools/test_distributed_takeout.py" line="351" time="0.484" /><testcase classname="tools.test_documentation" name="test_draft_excludes_paused_records_and_hides_marked_steps_without_removing_them" file="tools/test_documentation.py" line="53" time="0.247" /><testcase classname="tools.test_documentation" name="test_restart_and_delete_leave_no_draft_behind" file="tools/test_documentation.py" line="66" time="0.259" /><testcase classname="tools.test_documentation" name="test_fixed_document_is_signed_recorded_and_only_revisable" file="tools/test_documentation.py" line="78" time="0.287" /><testcase classname="tools.test_documentation" name="test_hidden_record_is_sealed_and_opens_only_with_a_matching_key" file="tools/test_documentation.py" line="100" time="0.252" /><testcase classname="tools.test_documentation" name="test_note_keeps_the_recorder_video_offset" file="tools/test_documentation.py" line="130" time="0.195" /><testcase classname="tools.test_documentation" name="test_appearance_changes_the_view_not_the_content" file="tools/test_documentation.py" line="144" time="0.242" /><testcase classname="tools.test_documentation" name="test_presentation_has_title_overview_steps_conclusions_and_checks" file="tools/test_documentation.py" line="163" time="0.251" /><testcase classname="tools.test_documentation" name="test_restricted_access_needs_chosen_chats" file="tools/test_documentation.py" line="175" time="0.000" /><testcase classname="tools.test_documentation_scope" name="test_admin_fixed_chat_selection_excludes_account_wide_private_data" file="tools/test_documentation_scope.py" line="66" time="0.248" /><testcase classname="tools.test_documentation_scope" name="test_hidden_subject_exports_use_only_provenance_and_keep_original_signed_source" file="tools/test_documentation_scope.py" line="87" time="0.212" /><testcase classname="tools.test_documentation_scope" name="test_annex_ignores_legacy_hidden_subject_metadata_without_mutating_model" file="tools/test_documentation_scope.py" line="127" time="0.000" /><testcase classname="tools.test_documentation_scope" name="test_legacy_frozen_broader_models_are_denied_without_rewriting_signed_bytes[undercover]" file="tools/test_documentation_scope.py" line="142" time="0.214" /><testcase classname="tools.test_documentation_scope" name="test_legacy_frozen_broader_models_are_denied_without_rewriting_signed_bytes[account]" file="tools/test_documentation_scope.py" line="142" time="0.218" /><testcase classname="tools.test_documentation_scope" name="test_legacy_frozen_broader_models_are_denied_without_rewriting_signed_bytes[other_chat]" file="tools/test_documentation_scope.py" line="142" time="0.219" /><testcase classname="tools.test_documentation_scope" name="test_legacy_frozen_broader_models_are_denied_without_rewriting_signed_bytes[unscoped_search]" file="tools/test_documentation_scope.py" line="142" time="0.230" /><testcase classname="tools.test_documentation_scope" name="test_all_frozen_document_routes_enforce_scope_and_package_choice_is_reachable" file="tools/test_documentation_scope.py" line="155" time="1.514" /><testcase classname="tools.test_documentation_scope" name="test_concurrent_fix_keeps_the_winning_documents_decryption_keys" file="tools/test_documentation_scope.py" line="193" time="0.525" /><testcase classname="tools.test_documentation_scope" name="test_failed_fixed_commit_leaves_retryable_draft_and_matching_keys" file="tools/test_documentation_scope.py" line="233" time="0.238" /><testcase classname="tools.test_download_ticket_quotas" name="test_owner_quota_spans_sessions_and_export_targets[False]" file="tools/test_download_ticket_quotas.py" line="25" time="0.001" /><testcase classname="tools.test_download_ticket_quotas" name="test_owner_quota_spans_sessions_and_export_targets[True]" file="tools/test_download_ticket_quotas.py" line="25" time="0.002" /><testcase classname="tools.test_download_ticket_quotas" name="test_global_quota_allows_1000_tickets_and_expiration_releases_capacity" file="tools/test_download_ticket_quotas.py" line="43" time="0.069" /><testcase classname="tools.test_download_ticket_quotas" name="test_http_tickets_isolate_grants_release_consumed_quota_and_recheck_revocation" file="tools/test_download_ticket_quotas.py" line="64" time="0.869" /><testcase classname="tools.test_dstack_archive_limits" name="test_normal_image_and_path_traversal_allowlist" file="tools/test_dstack_archive_limits.py" line="55" time="0.008" /><testcase classname="tools.test_dstack_archive_limits" name="test_links_and_special_files_are_refused[2]" file="tools/test_dstack_archive_limits.py" line="64" time="0.005" /><testcase classname="tools.test_dstack_archive_limits" name="test_links_and_special_files_are_refused[1]" file="tools/test_dstack_archive_limits.py" line="64" time="0.004" /><testcase classname="tools.test_dstack_archive_limits" name="test_links_and_special_files_are_refused[6]" file="tools/test_dstack_archive_limits.py" line="64" time="0.004" /><testcase classname="tools.test_dstack_archive_limits" name="test_duplicate_file_is_refused" file="tools/test_dstack_archive_limits.py" line="72" time="0.003" /><testcase classname="tools.test_dstack_archive_limits" name="test_member_size_is_checked_before_reading" file="tools/test_dstack_archive_limits.py" line="79" time="0.001" /><testcase classname="tools.test_dstack_archive_limits" name="test_discarded_members_still_use_decompression_budget" file="tools/test_dstack_archive_limits.py" line="87" time="0.002" /><testcase classname="tools.test_dstack_archive_limits" name="test_member_count_is_bounded" file="tools/test_dstack_archive_limits.py" line="95" time="0.002" /><testcase classname="tools.test_dstack_archive_limits" name="test_pax_metadata_uses_decompression_budget" file="tools/test_dstack_archive_limits.py" line="102" time="0.002" /><testcase classname="tools.test_dstack_archive_limits" name="test_truncated_member_is_rejected" file="tools/test_dstack_archive_limits.py" line="111" time="0.001" /><testcase classname="tools.test_ephemeral_media" name="test_saved_file_ttl_signature_and_viewing_label[10-photo]" file="tools/test_ephemeral_media.py" line="67" time="0.240" /><testcase classname="tools.test_ephemeral_media" name="test_saved_file_ttl_signature_and_viewing_label[10-video]" file="tools/test_ephemeral_media.py" line="67" time="0.236" /><testcase classname="tools.test_ephemeral_media" name="test_saved_file_ttl_signature_and_viewing_label[10-document]" file="tools/test_ephemeral_media.py" line="67" time="0.246" /><testcase classname="tools.test_ephemeral_media" name="test_saved_file_ttl_signature_and_viewing_label[2147483647-photo]" file="tools/test_ephemeral_media.py" line="67" time="0.228" /><testcase classname="tools.test_ephemeral_media" name="test_saved_file_ttl_signature_and_viewing_label[2147483647-video]" file="tools/test_ephemeral_media.py" line="67" time="0.253" /><testcase classname="tools.test_ephemeral_media" name="test_saved_file_ttl_signature_and_viewing_label[2147483647-document]" file="tools/test_ephemeral_media.py" line="67" time="0.260" /><testcase classname="tools.test_ephemeral_media" name="test_empty_media_is_signed_unavailable_even_when_downloads_disabled[photo]" file="tools/test_ephemeral_media.py" line="98" time="0.250" /><testcase classname="tools.test_ephemeral_media" name="test_empty_media_is_signed_unavailable_even_when_downloads_disabled[video]" file="tools/test_ephemeral_media.py" line="98" time="0.250" /><testcase classname="tools.test_ephemeral_media" name="test_empty_media_is_signed_unavailable_even_when_downloads_disabled[document]" file="tools/test_ephemeral_media.py" line="98" time="0.255" /><testcase classname="tools.test_ephemeral_media" name="test_bypasses_type_and_duration_rules_but_can_be_disabled" file="tools/test_ephemeral_media.py" line="117" time="0.293" /><testcase classname="tools.test_ephemeral_media" name="test_no_bytes_for_explicit_exclusions_or_size_limit[settings0-None]" file="tools/test_ephemeral_media.py" line="137" time="0.258" /><testcase classname="tools.test_ephemeral_media" name="test_no_bytes_for_explicit_exclusions_or_size_limit[settings1-None]" file="tools/test_ephemeral_media.py" line="137" time="0.252" /><testcase classname="tools.test_ephemeral_media" name="test_no_bytes_for_explicit_exclusions_or_size_limit[settings2-2097152]" file="tools/test_ephemeral_media.py" line="137" time="0.239" /><testcase classname="tools.test_ephemeral_media" name="test_no_bytes_for_explicit_exclusions_or_size_limit[settings3-None]" file="tools/test_ephemeral_media.py" line="137" time="0.240" /><testcase classname="tools.test_ephemeral_media" name="test_saved_observation_survives_expired_reference_and_missing_media" file="tools/test_ephemeral_media.py" line="161" time="0.236" /><testcase classname="tools.test_ephemeral_media" name="test_queue_cancellation_retains_ephemeral_outcome" file="tools/test_ephemeral_media.py" line="179" time="0.238" /><testcase classname="tools.test_ephemeral_media" name="test_outcomes_for_old_signed_observations_derive_ttl_from_raw" file="tools/test_ephemeral_media.py" line="186" time="0.225" /><testcase classname="tools.test_ephemeral_media" name="test_immediate_lane_works_during_bulk_download_and_messages_first" file="tools/test_ephemeral_media.py" line="192" time="0.294" /><testcase classname="tools.test_ephemeral_media" name="test_history_saves_ephemeral_before_next_page_without_waiting_for_ordinary_jobs" file="tools/test_ephemeral_media.py" line="230" time="0.714" /><testcase classname="tools.test_ephemeral_media" name="test_explicit_empty_constructors_are_unavailable[photo]" file="tools/test_ephemeral_media.py" line="257" time="0.000" /><testcase classname="tools.test_ephemeral_media" name="test_explicit_empty_constructors_are_unavailable[document]" file="tools/test_ephemeral_media.py" line="257" time="0.000" /><testcase classname="tools.test_ephemeral_media" name="test_disabled_or_absent_ttl_is_not_ephemeral[None]" file="tools/test_ephemeral_media.py" line="264" time="0.000" /><testcase classname="tools.test_ephemeral_media" name="test_disabled_or_absent_ttl_is_not_ephemeral[0]" file="tools/test_ephemeral_media.py" line="264" time="0.000" /><testcase classname="tools.test_ephemeral_media" name="test_disabled_or_absent_ttl_is_not_ephemeral[-1]" file="tools/test_ephemeral_media.py" line="264" time="0.000" /><testcase classname="tools.test_ephemeral_media" name="test_no_read_receipt_reaches_transport_even_in_wrappers_or_batches[direct-ReadHistoryRequest0]" file="tools/test_ephemeral_media.py" line="272" time="0.001" /><testcase classname="tools.test_ephemeral_media" name="test_no_read_receipt_reaches_transport_even_in_wrappers_or_batches[direct-ReadMessageContentsRequest0]" file="tools/test_ephemeral_media.py" line="272" time="0.001" /><testcase classname="tools.test_ephemeral_media" name="test_no_read_receipt_reaches_transport_even_in_wrappers_or_batches[direct-ReadHistoryRequest1]" file="tools/test_ephemeral_media.py" line="272" time="0.001" /><testcase classname="tools.test_ephemeral_media" name="test_no_read_receipt_reaches_transport_even_in_wrappers_or_batches[direct-ReadMessageContentsRequest1]" file="tools/test_ephemeral_media.py" line="272" time="0.001" /><testcase classname="tools.test_ephemeral_media" name="test_no_read_receipt_reaches_transport_even_in_wrappers_or_batches[direct-ReadDiscussionRequest]" file="tools/test_ephemeral_media.py" line="272" time="0.001" /><testcase classname="tools.test_ephemeral_media" name="test_no_read_receipt_reaches_transport_even_in_wrappers_or_batches[direct-ReadMentionsRequest]" file="tools/test_ephemeral_media.py" line="272" time="0.001" /><testcase classname="tools.test_ephemeral_media" name="test_no_read_receipt_reaches_transport_even_in_wrappers_or_batches[direct-ReadReactionsRequest]" file="tools/test_ephemeral_media.py" line="272" time="0.001" /><testcase classname="tools.test_ephemeral_media" name="test_no_read_receipt_reaches_transport_even_in_wrappers_or_batches[direct-ReadEncryptedHistoryRequest]" file="tools/test_ephemeral_media.py" line="272" time="0.001" /><testcase classname="tools.test_ephemeral_media" name="test_no_read_receipt_reaches_transport_even_in_wrappers_or_batches[direct-ReadStoriesRequest]" file="tools/test_ephemeral_media.py" line="272" time="0.001" /><testcase classname="tools.test_ephemeral_media" name="test_no_read_receipt_reaches_transport_even_in_wrappers_or_batches[batch-ReadHistoryRequest0]" file="tools/test_ephemeral_media.py" line="272" time="0.001" /><testcase classname="tools.test_ephemeral_media" name="test_no_read_receipt_reaches_transport_even_in_wrappers_or_batches[batch-ReadMessageContentsRequest0]" file="tools/test_ephemeral_media.py" line="272" time="0.001" /><testcase classname="tools.test_ephemeral_media" name="test_no_read_receipt_reaches_transport_even_in_wrappers_or_batches[batch-ReadHistoryRequest1]" file="tools/test_ephemeral_media.py" line="272" time="0.001" /><testcase classname="tools.test_ephemeral_media" name="test_no_read_receipt_reaches_transport_even_in_wrappers_or_batches[batch-ReadMessageContentsRequest1]" file="tools/test_ephemeral_media.py" line="272" time="0.001" /><testcase classname="tools.test_ephemeral_media" name="test_no_read_receipt_reaches_transport_even_in_wrappers_or_batches[batch-ReadDiscussionRequest]" file="tools/test_ephemeral_media.py" line="272" time="0.001" /><testcase classname="tools.test_ephemeral_media" name="test_no_read_receipt_reaches_transport_even_in_wrappers_or_batches[batch-ReadMentionsRequest]" file="tools/test_ephemeral_media.py" line="272" time="0.001" /><testcase classname="tools.test_ephemeral_media" name="test_no_read_receipt_reaches_transport_even_in_wrappers_or_batches[batch-ReadReactionsRequest]" file="tools/test_ephemeral_media.py" line="272" time="0.001" /><testcase classname="tools.test_ephemeral_media" name="test_no_read_receipt_reaches_transport_even_in_wrappers_or_batches[batch-ReadEncryptedHistoryRequest]" file="tools/test_ephemeral_media.py" line="272" time="0.001" /><testcase classname="tools.test_ephemeral_media" name="test_no_read_receipt_reaches_transport_even_in_wrappers_or_batches[batch-ReadStoriesRequest]" file="tools/test_ephemeral_media.py" line="272" time="0.001" /><testcase classname="tools.test_ephemeral_media" name="test_no_read_receipt_reaches_transport_even_in_wrappers_or_batches[takeout-ReadHistoryRequest0]" file="tools/test_ephemeral_media.py" line="272" time="0.001" /><testcase classname="tools.test_ephemeral_media" name="test_no_read_receipt_reaches_transport_even_in_wrappers_or_batches[takeout-ReadMessageContentsRequest0]" file="tools/test_ephemeral_media.py" line="272" time="0.001" /><testcase classname="tools.test_ephemeral_media" name="test_no_read_receipt_reaches_transport_even_in_wrappers_or_batches[takeout-ReadHistoryRequest1]" file="tools/test_ephemeral_media.py" line="272" time="0.001" /><testcase classname="tools.test_ephemeral_media" name="test_no_read_receipt_reaches_transport_even_in_wrappers_or_batches[takeout-ReadMessageContentsRequest1]" file="tools/test_ephemeral_media.py" line="272" time="0.001" /><testcase classname="tools.test_ephemeral_media" name="test_no_read_receipt_reaches_transport_even_in_wrappers_or_batches[takeout-ReadDiscussionRequest]" file="tools/test_ephemeral_media.py" line="272" time="0.001" /><testcase classname="tools.test_ephemeral_media" name="test_no_read_receipt_reaches_transport_even_in_wrappers_or_batches[takeout-ReadMentionsRequest]" file="tools/test_ephemeral_media.py" line="272" time="0.001" /><testcase classname="tools.test_ephemeral_media" name="test_no_read_receipt_reaches_transport_even_in_wrappers_or_batches[takeout-ReadReactionsRequest]" file="tools/test_ephemeral_media.py" line="272" time="0.001" /><testcase classname="tools.test_ephemeral_media" name="test_no_read_receipt_reaches_transport_even_in_wrappers_or_batches[takeout-ReadEncryptedHistoryRequest]" file="tools/test_ephemeral_media.py" line="272" time="0.001" /><testcase classname="tools.test_ephemeral_media" name="test_no_read_receipt_reaches_transport_even_in_wrappers_or_batches[takeout-ReadStoriesRequest]" file="tools/test_ephemeral_media.py" line="272" time="0.001" /><testcase classname="tools.test_ephemeral_media" name="test_no_read_receipt_reaches_transport_even_in_wrappers_or_batches[nested-ReadHistoryRequest0]" file="tools/test_ephemeral_media.py" line="272" time="0.001" /><testcase classname="tools.test_ephemeral_media" name="test_no_read_receipt_reaches_transport_even_in_wrappers_or_batches[nested-ReadMessageContentsRequest0]" file="tools/test_ephemeral_media.py" line="272" time="0.001" /><testcase classname="tools.test_ephemeral_media" name="test_no_read_receipt_reaches_transport_even_in_wrappers_or_batches[nested-ReadHistoryRequest1]" file="tools/test_ephemeral_media.py" line="272" time="0.001" /><testcase classname="tools.test_ephemeral_media" name="test_no_read_receipt_reaches_transport_even_in_wrappers_or_batches[nested-ReadMessageContentsRequest1]" file="tools/test_ephemeral_media.py" line="272" time="0.001" /><testcase classname="tools.test_ephemeral_media" name="test_no_read_receipt_reaches_transport_even_in_wrappers_or_batches[nested-ReadDiscussionRequest]" file="tools/test_ephemeral_media.py" line="272" time="0.001" /><testcase classname="tools.test_ephemeral_media" name="test_no_read_receipt_reaches_transport_even_in_wrappers_or_batches[nested-ReadMentionsRequest]" file="tools/test_ephemeral_media.py" line="272" time="0.001" /><testcase classname="tools.test_ephemeral_media" name="test_no_read_receipt_reaches_transport_even_in_wrappers_or_batches[nested-ReadReactionsRequest]" file="tools/test_ephemeral_media.py" line="272" time="0.001" /><testcase classname="tools.test_ephemeral_media" name="test_no_read_receipt_reaches_transport_even_in_wrappers_or_batches[nested-ReadEncryptedHistoryRequest]" file="tools/test_ephemeral_media.py" line="272" time="0.001" /><testcase classname="tools.test_ephemeral_media" name="test_no_read_receipt_reaches_transport_even_in_wrappers_or_batches[nested-ReadStoriesRequest]" file="tools/test_ephemeral_media.py" line="272" time="0.001" /><testcase classname="tools.test_ephemeral_media" name="test_no_read_receipt_reaches_transport_even_in_wrappers_or_batches[generator-ReadHistoryRequest0]" file="tools/test_ephemeral_media.py" line="272" time="0.001" /><testcase classname="tools.test_ephemeral_media" name="test_no_read_receipt_reaches_transport_even_in_wrappers_or_batches[generator-ReadMessageContentsRequest0]" file="tools/test_ephemeral_media.py" line="272" time="0.000" /><testcase classname="tools.test_ephemeral_media" name="test_no_read_receipt_reaches_transport_even_in_wrappers_or_batches[generator-ReadHistoryRequest1]" file="tools/test_ephemeral_media.py" line="272" time="0.001" /><testcase classname="tools.test_ephemeral_media" name="test_no_read_receipt_reaches_transport_even_in_wrappers_or_batches[generator-ReadMessageContentsRequest1]" file="tools/test_ephemeral_media.py" line="272" time="0.001" /><testcase classname="tools.test_ephemeral_media" name="test_no_read_receipt_reaches_transport_even_in_wrappers_or_batches[generator-ReadDiscussionRequest]" file="tools/test_ephemeral_media.py" line="272" time="0.001" /><testcase classname="tools.test_ephemeral_media" name="test_no_read_receipt_reaches_transport_even_in_wrappers_or_batches[generator-ReadMentionsRequest]" file="tools/test_ephemeral_media.py" line="272" time="0.001" /><testcase classname="tools.test_ephemeral_media" name="test_no_read_receipt_reaches_transport_even_in_wrappers_or_batches[generator-ReadReactionsRequest]" file="tools/test_ephemeral_media.py" line="272" time="0.000" /><testcase classname="tools.test_ephemeral_media" name="test_no_read_receipt_reaches_transport_even_in_wrappers_or_batches[generator-ReadEncryptedHistoryRequest]" file="tools/test_ephemeral_media.py" line="272" time="0.001" /><testcase classname="tools.test_ephemeral_media" name="test_no_read_receipt_reaches_transport_even_in_wrappers_or_batches[generator-ReadStoriesRequest]" file="tools/test_ephemeral_media.py" line="272" time="0.001" /><testcase classname="tools.test_ephemeral_media" name="test_real_telethon_read_helper_is_blocked" file="tools/test_ephemeral_media.py" line="289" time="0.001" /><testcase classname="tools.test_ephemeral_media" name="test_real_telethon_downloader_fetches_view_once_bytes_without_read_receipts[photo]" file="tools/test_ephemeral_media.py" line="301" time="0.001" /><testcase classname="tools.test_ephemeral_media" name="test_real_telethon_downloader_fetches_view_once_bytes_without_read_receipts[video]" file="tools/test_ephemeral_media.py" line="301" time="0.001" /><testcase classname="tools.test_ephemeral_media" name="test_real_telethon_downloader_fetches_view_once_bytes_without_read_receipts[document]" file="tools/test_ephemeral_media.py" line="301" time="0.001" /><testcase classname="tools.test_ephemeral_media" name="test_normalization_retains_setting" file="tools/test_ephemeral_media.py" line="323" time="0.000" /><testcase classname="tools.test_ephemeral_media" name="test_preflight_counts_ttl_bytes_with_excluded_type" file="tools/test_ephemeral_media.py" line="328" time="0.222" /><testcase classname="tools.test_ephemeral_media" name="test_merged_backfill_preserves_ttl_using_the_selected_transport[standard]" file="tools/test_ephemeral_media.py" line="338" time="0.553" /><testcase classname="tools.test_ephemeral_media" name="test_merged_backfill_preserves_ttl_using_the_selected_transport[takeout]" file="tools/test_ephemeral_media.py" line="338" time="0.599" /><testcase classname="tools.test_evidence_checks" name="test_failing_pytest_body_and_plain_check_both_execute[evidence]" file="tools/test_evidence_checks.py" line="11" time="0.205" /><testcase classname="tools.test_evidence_checks" name="test_failing_pytest_body_and_plain_check_both_execute[browser]" file="tools/test_evidence_checks.py" line="11" time="0.203" /><testcase classname="tools.test_evidence_checks" name="test_failing_pytest_body_and_plain_check_both_execute[browser-ux]" file="tools/test_evidence_checks.py" line="11" time="0.202" /><testcase classname="tools.test_evidence_checks" name="test_failing_pytest_body_and_plain_check_both_execute[site]" file="tools/test_evidence_checks.py" line="11" time="0.208" /><testcase classname="tools.test_evidence_checks" name="test_empty_test_module_cannot_report_success" file="tools/test_evidence_checks.py" line="28" time="0.184" /><testcase classname="tools.test_evidence_checks" name="test_list_suites_does_not_run_checks_or_create_output" file="tools/test_evidence_checks.py" line="41" time="0.001" /><testcase classname="tools.test_export_archive_name" name="test_chat_titles_become_safe_file_names" file="tools/test_export_archive_name.py" line="34" time="0.198" /><testcase classname="tools.test_export_archive_name" name="test_number_counts_todays_exports_of_the_same_chat" file="tools/test_export_archive_name.py" line="46" time="0.218" /><testcase classname="tools.test_export_archive_name" name="test_distributed_exports_of_one_chat_are_numbered" file="tools/test_export_archive_name.py" line="58" time="2.752" /><testcase classname="tools.test_export_archive_name" name="test_single_chat_export_names_its_archive" file="tools/test_export_archive_name.py" line="78" time="0.280" /><testcase classname="tools.test_export_budget" name="test_budget_spends_only_the_remaining_session_and_reserves_packaging" file="tools/test_export_budget.py" line="24" time="0.000" /><testcase classname="tools.test_export_budget" name="test_large_files_do_not_fit_and_text_only_recalculation_changes_the_plan" file="tools/test_export_budget.py" line="34" time="0.000" /><testcase classname="tools.test_export_budget" name="test_incomplete_measurements_cannot_claim_the_whole_selection_fits[change0-options0]" file="tools/test_export_budget.py" line="42" time="0.000" /><testcase classname="tools.test_export_budget" name="test_incomplete_measurements_cannot_claim_the_whole_selection_fits[change1-options1]" file="tools/test_export_budget.py" line="42" time="0.000" /><testcase classname="tools.test_export_budget" name="test_incomplete_measurements_cannot_claim_the_whole_selection_fits[change2-options2]" file="tools/test_export_budget.py" line="42" time="0.000" /><testcase classname="tools.test_export_budget" name="test_incomplete_measurements_cannot_claim_the_whole_selection_fits[change3-options3]" file="tools/test_export_budget.py" line="42" time="0.000" /><testcase classname="tools.test_export_budget" name="test_incomplete_measurements_cannot_claim_the_whole_selection_fits[change4-options4]" file="tools/test_export_budget.py" line="42" time="0.000" /><testcase classname="tools.test_export_budget" name="test_incomplete_measurements_cannot_claim_the_whole_selection_fits[change5-options5]" file="tools/test_export_budget.py" line="42" time="0.000" /><testcase classname="tools.test_export_budget" name="test_unknown_totals_and_file_sizes_remain_explicit" file="tools/test_export_budget.py" line="54" time="0.000" /><testcase classname="tools.test_export_budget" name="test_waits_and_actual_slow_transfers_revise_the_time_budget" file="tools/test_export_budget.py" line="62" time="0.000" /><testcase classname="tools.test_export_budget" name="test_packaging_starts_before_the_session_deadline_and_preserves_a_verified_partial" file="tools/test_export_budget.py" line="73" time="0.924" /><testcase classname="tools.test_export_plan" name="test_public_channel_plan_picks_idle_accounts_without_reserving_them" file="tools/test_export_plan.py" line="98" time="0.001" /><testcase classname="tools.test_export_plan" name="test_idle_reader_is_reserved_only_while_reading" file="tools/test_export_plan.py" line="121" time="0.000" /><testcase classname="tools.test_export_plan" name="test_private_invite_without_membership_and_person_links_are_not_exportable" file="tools/test_export_plan.py" line="128" time="0.000" /><testcase classname="tools.test_export_plan" name="test_basic_group_takes_one_member_and_marks_non_members" file="tools/test_export_plan.py" line="137" time="0.000" /><testcase classname="tools.test_export_plan" name="test_measured_rates_replace_defaults" file="tools/test_export_plan.py" line="147" time="0.000" /><testcase classname="tools.test_export_plan" name="test_restricted_chat_is_rejected_before_reading_history_or_channel_details" file="tools/test_export_plan.py" line="155" time="0.000" /><testcase classname="tools.test_export_plan" name="test_basic_group_never_selects_multiple_eligible_members" file="tools/test_export_plan.py" line="165" time="0.000" /><testcase classname="tools.test_export_plan" name="test_unavailable_account_scopes_do_not_contribute_benchmark_rates" file="tools/test_export_plan.py" line="172" time="0.000" /><testcase classname="tools.test_export_plan" name="test_planner_cancellation_releases_its_temporary_reservation" file="tools/test_export_plan.py" line="182" time="0.000" /><testcase classname="tools.test_export_plan" name="test_planner_api_honors_export_and_chat_grants" file="tools/test_export_plan.py" line="200" time="0.729" /><testcase classname="tools.test_export_plan" name="test_unknown_username_and_bad_links_are_readable_errors" file="tools/test_export_plan.py" line="229" time="0.001" /><testcase classname="tools.test_export_plan" name="test_large_chat_spreads_over_accounts_and_estimates_fall" file="tools/test_export_plan.py" line="239" time="0.001" /><testcase classname="tools.test_exported_authorization" name="test_exported_sender_authorization_loss_is_not_session_loss[SessionRevokedError]" file="tools/test_exported_authorization.py" line="30" time="0.002" /><testcase classname="tools.test_exported_authorization" name="test_exported_sender_authorization_loss_is_not_session_loss[AuthKeyUnregisteredError]" file="tools/test_exported_authorization.py" line="30" time="0.003" /><testcase classname="tools.test_exported_authorization" name="test_borrowed_stale_sender_waits_for_every_return" file="tools/test_exported_authorization.py" line="55" time="0.002" /><testcase classname="tools.test_exported_authorization" name="test_account_level_errors_from_exported_sender_still_escalate" file="tools/test_exported_authorization.py" line="74" time="0.002" /><testcase classname="tools.test_exported_authorization" name="test_collector_keeps_observing_when_a_file_data_center_authorization_ends" file="tools/test_exported_authorization.py" line="88" time="0.235" /><testcase classname="tools.test_extensions" name="test_reader_offers_no_writes" file="tools/test_extensions.py" line="42" time="0.193" /><testcase classname="tools.test_extensions" name="test_analyzer_plugs_in_and_respects_the_witness_goal" file="tools/test_extensions.py" line="49" time="0.212" /><testcase classname="tools.test_extensions" name="test_workspace_goal_prefers_the_saved_preset" file="tools/test_extensions.py" line="62" time="0.211" /><testcase classname="tools.test_file_hash_export" name="test_hashes_dc_migration_last_range_and_comparison" file="tools/test_file_hash_export.py" line="65" time="0.007" /><testcase classname="tools.test_file_hash_export" name="test_incomplete_coverage_cannot_be_promoted_to_complete" file="tools/test_file_hash_export.py" line="82" time="0.002" /><testcase classname="tools.test_file_hash_export" name="test_hashes_use_media_dc_without_relying_on_migration_error" file="tools/test_file_hash_export.py" line="95" time="0.001" /><testcase classname="tools.test_file_hash_export" name="test_photo_variant_is_explicit" file="tools/test_file_hash_export.py" line="107" time="0.000" /><testcase classname="tools.test_file_hash_export" name="test_media_policy_classification_is_independent_of_attribute_order[photo]" file="tools/test_file_hash_export.py" line="132" time="0.001" /><testcase classname="tools.test_file_hash_export" name="test_media_policy_classification_is_independent_of_attribute_order[video]" file="tools/test_file_hash_export.py" line="132" time="0.001" /><testcase classname="tools.test_file_hash_export" name="test_media_policy_classification_is_independent_of_attribute_order[video_message]" file="tools/test_file_hash_export.py" line="132" time="0.001" /><testcase classname="tools.test_file_hash_export" name="test_media_policy_classification_is_independent_of_attribute_order[voice]" file="tools/test_file_hash_export.py" line="132" time="0.001" /><testcase classname="tools.test_file_hash_export" name="test_media_policy_classification_is_independent_of_attribute_order[audio]" file="tools/test_file_hash_export.py" line="132" time="0.001" /><testcase classname="tools.test_file_hash_export" name="test_media_policy_classification_is_independent_of_attribute_order[document]" file="tools/test_file_hash_export.py" line="132" time="0.001" /><testcase classname="tools.test_file_hash_export" name="test_media_policy_classification_is_independent_of_attribute_order[animation]" file="tools/test_file_hash_export.py" line="132" time="0.001" /><testcase classname="tools.test_file_hash_export" name="test_media_policy_classification_is_independent_of_attribute_order[sticker]" file="tools/test_file_hash_export.py" line="132" time="0.001" /><testcase classname="tools.test_file_hash_export" name="test_all_media_policies_preserve_messages_and_verify[download]" file="tools/test_file_hash_export.py" line="176" time="0.778" /><testcase classname="tools.test_file_hash_export" name="test_all_media_policies_preserve_messages_and_verify[hashes_only]" file="tools/test_file_hash_export.py" line="176" time="0.700" /><testcase classname="tools.test_file_hash_export" name="test_all_media_policies_preserve_messages_and_verify[exclude]" file="tools/test_file_hash_export.py" line="176" time="0.629" /><testcase classname="tools.test_file_hash_export" name="test_all_media_policies_preserve_messages_and_verify[mixed]" file="tools/test_file_hash_export.py" line="176" time="0.701" /><testcase classname="tools.test_file_hash_export" name="test_all_media_policies_preserve_messages_and_verify[budget_exhausted]" file="tools/test_file_hash_export.py" line="176" time="0.736" /><testcase classname="tools.test_file_hash_export" name="test_signed_hash_only_export_reuses_reference_and_verifies" file="tools/test_file_hash_export.py" line="244" time="0.700" /><testcase classname="tools.test_file_hash_export" name="test_additional_data_stream_return_and_unknown_length" file="tools/test_file_hash_export.py" line="288" time="0.025" /><testcase classname="tools.test_file_hash_export" name="test_download_dedup_budget_and_unique_bytes" file="tools/test_file_hash_export.py" line="314" time="0.684" /><testcase classname="tools.test_file_hash_export" name="test_single_chat_hash_policy_and_signed_bundle" file="tools/test_file_hash_export.py" line="351" time="0.743" /><testcase classname="tools.test_file_hash_export" name="test_preflight_unknown_totals_and_static_errors" file="tools/test_file_hash_export.py" line="385" time="0.000" /><testcase classname="tools.test_file_hash_export" name="test_preflight_is_bounded_and_downloads_nothing" file="tools/test_file_hash_export.py" line="393" time="0.003" /><testcase classname="tools.test_fulltext" name="test_word_forms_share_one_term" file="tools/test_fulltext.py" line="64" time="0.001" /><testcase classname="tools.test_fulltext" name="test_requirements_examples" file="tools/test_fulltext.py" line="72" time="0.644" /><testcase classname="tools.test_fulltext" name="test_references_and_filters" file="tools/test_fulltext.py" line="84" time="0.291" /><testcase classname="tools.test_fulltext" name="test_period_and_phrase_use_the_journal_when_needed" file="tools/test_fulltext.py" line="107" time="0.249" /><testcase classname="tools.test_fulltext" name="test_ranking_prefers_dense_matches" file="tools/test_fulltext.py" line="129" time="0.373" /><testcase classname="tools.test_fulltext" name="test_ukrainian_without_gpl_dictionary" file="tools/test_fulltext.py" line="143" time="0.227" /><testcase classname="tools.test_fulltext" name="test_index_follows_the_signed_journal" file="tools/test_fulltext.py" line="164" time="0.441" /><testcase classname="tools.test_fulltext" name="test_machine_recognition_is_separate_derived_data" file="tools/test_fulltext.py" line="218" time="0.340" /><testcase classname="tools.test_fulltext" name="test_archive_reader_ranked_search_respects_scope" file="tools/test_fulltext.py" line="245" time="0.286" /><testcase classname="tools.test_fulltext" name="test_ask_the_archive_uses_ranked_retrieval" file="tools/test_fulltext.py" line="258" time="0.528" /><testcase classname="tools.test_fulltext" name="test_ranked_results_page_through_every_match" file="tools/test_fulltext.py" line="279" time="0.554" /><testcase classname="tools.test_fulltext" name="test_ranked_pagination_stays_inside_the_result_window" file="tools/test_fulltext.py" line="297" time="1.463" /><testcase classname="tools.test_fulltext" name="test_newest_pages_keep_recognition_and_message_order[sources0]" file="tools/test_fulltext.py" line="313" time="0.685" /><testcase classname="tools.test_fulltext" name="test_newest_pages_keep_recognition_and_message_order[sources1]" file="tools/test_fulltext.py" line="313" time="0.695" /><testcase classname="tools.test_fulltext" name="test_newest_pages_keep_recognition_and_message_order[sources2]" file="tools/test_fulltext.py" line="313" time="0.753" /><testcase classname="tools.test_fulltext" name="test_match_offsets_survive_combined_unicode_changes[expansion-before-removal]" file="tools/test_fulltext.py" line="333" time="0.000" /><testcase classname="tools.test_fulltext" name="test_match_offsets_survive_combined_unicode_changes[removal-before-expansion]" file="tools/test_fulltext.py" line="333" time="0.000" /><testcase classname="tools.test_fulltext" name="test_match_offsets_survive_combined_unicode_changes[combining]" file="tools/test_fulltext.py" line="333" time="0.000" /><testcase classname="tools.test_fulltext" name="test_match_offsets_survive_combined_unicode_changes[ligature]" file="tools/test_fulltext.py" line="333" time="0.000" /><testcase classname="tools.test_fulltext" name="test_long_questions_still_use_the_index" file="tools/test_fulltext.py" line="341" time="0.347" /><testcase classname="tools.test_fulltext" name="test_excerpt_follows_the_match_past_invisible_characters" file="tools/test_fulltext.py" line="355" time="0.364" /><testcase classname="tools.test_fulltext" name="test_api_and_scoped_access" file="tools/test_fulltext.py" line="365" time="0.855" /><testcase classname="tools.test_fulltext" name="test_cli_keeps_stdout_structured" file="tools/test_fulltext.py" line="404" time="0.783" /><testcase classname="tools.test_fulltext" name="test_verifier_accepts_archive_from_before_full_text" file="tools/test_fulltext.py" line="426" time="0.006" /><testcase classname="tools.test_fulltext" name="test_previous_verifier_accepts_current_archive" file="tools/test_fulltext.py" line="431" time="1.108" /><testcase classname="tools.test_gap_analysis" name="test_gaps_are_counted_and_anchored" file="tools/test_gap_analysis.py" line="35" time="0.000" /><testcase classname="tools.test_gap_analysis" name="test_channel_numbering_is_valid_per_chat_but_not_per_sender" file="tools/test_gap_analysis.py" line="55" time="0.000" /><testcase classname="tools.test_gap_analysis" name="test_account_sequence_needs_whole_account_collection" file="tools/test_gap_analysis.py" line="73" time="0.000" /><testcase classname="tools.test_gap_analysis" name="test_capture_status_reports_gaps_within_access" file="tools/test_gap_analysis.py" line="115" time="0.310" /><testcase classname="tools.test_gap_analysis" name="test_export_report_and_verifier_carry_the_measurement" file="tools/test_gap_analysis.py" line="134" time="1.136" /><testcase classname="tools.test_gap_analysis" name="test_report_rows_and_parameters_are_described" file="tools/test_gap_analysis.py" line="163" time="0.000" /><testcase classname="tools.test_gap_analysis" name="test_service_numbers_are_observed_once_and_estimated_inside_the_window" file="tools/test_gap_analysis.py" line="173" time="0.000" /><testcase classname="tools.test_gap_analysis" name="test_applied_scope_needs_explicit_own_message_coverage" file="tools/test_gap_analysis.py" line="185" time="0.000" /><testcase classname="tools.test_gap_analysis" name="test_stopped_collection_does_not_extend_account_measurement" file="tools/test_gap_analysis.py" line="198" time="0.343" /><testcase classname="tools.test_gap_analysis" name="test_expired_capture_budget_returns_partial_without_poisoning_later_reads" file="tools/test_gap_analysis.py" line="211" time="0.334" /><testcase classname="tools.test_gap_analysis" name="test_gap_parameters_reject_invalid_types_and_ranges[settings0]" file="tools/test_gap_analysis.py" line="218" time="0.000" /><testcase classname="tools.test_gap_analysis" name="test_gap_parameters_reject_invalid_types_and_ranges[settings1]" file="tools/test_gap_analysis.py" line="218" time="0.000" /><testcase classname="tools.test_gap_analysis" name="test_gap_parameters_reject_invalid_types_and_ranges[settings2]" file="tools/test_gap_analysis.py" line="218" time="0.000" /><testcase classname="tools.test_gap_analysis" name="test_gap_parameters_reject_invalid_types_and_ranges[settings3]" file="tools/test_gap_analysis.py" line="218" time="0.000" /><testcase classname="tools.test_history_backfill" name="test_text_finishes_while_media_waits_then_resume_uses_durable_queue" file="tools/test_history_backfill.py" line="104" time="0.563" /><testcase classname="tools.test_history_backfill" name="test_resume_rejects_mutable_cursor_tampering_before_network[offset_id=1]" file="tools/test_history_backfill.py" line="136" time="0.415" /><testcase classname="tools.test_history_backfill" name="test_resume_rejects_mutable_cursor_tampering_before_network[metadata='{}']" file="tools/test_history_backfill.py" line="136" time="0.381" /><testcase classname="tools.test_history_backfill" name="test_resume_rejects_mutable_cursor_tampering_before_network[captured=800]" file="tools/test_history_backfill.py" line="136" time="0.390" /><testcase classname="tools.test_history_backfill" name="test_resume_rejects_mutable_cursor_tampering_before_network[cursor_seq=1]" file="tools/test_history_backfill.py" line="136" time="0.392" /><testcase classname="tools.test_history_backfill" name="test_atomic_message_cursor_and_media_rollback" file="tools/test_history_backfill.py" line="156" time="0.571" /><testcase classname="tools.test_history_backfill" name="test_changed_observation_is_not_a_fabricated_edit_or_deletion" file="tools/test_history_backfill.py" line="179" time="0.493" /><testcase classname="tools.test_history_backfill" name="test_admin_log_retains_historical_versions_without_overwriting_chat[False]" file="tools/test_history_backfill.py" line="195" time="0.766" /><testcase classname="tools.test_history_backfill" name="test_admin_log_retains_historical_versions_without_overwriting_chat[True]" file="tools/test_history_backfill.py" line="195" time="0.801" /><testcase classname="tools.test_history_backfill" name="test_admin_rights_denied_is_reported_as_gap_not_empty_success" file="tools/test_history_backfill.py" line="219" time="0.615" /><testcase classname="tools.test_history_backfill" name="test_takeout_ranges_wrap_files_and_finalize_only_after_drain" file="tools/test_history_backfill.py" line="233" time="0.707" /><testcase classname="tools.test_history_backfill" name="test_takeout_approval_does_not_destroy_login_or_start_history" file="tools/test_history_backfill.py" line="253" time="0.279" /><testcase classname="tools.test_history_backfill" name="test_expired_takeout_resumes_without_skipping_or_switching_account" file="tools/test_history_backfill.py" line="272" time="0.549" /><testcase classname="tools.test_history_backfill" name="test_changed_takeout_ranges_fail_closed" file="tools/test_history_backfill.py" line="292" time="0.382" /><testcase classname="tools.test_history_backfill" name="test_pacer_floors_account_isolation_and_takeout_recognition" file="tools/test_history_backfill.py" line="310" time="3.923" /><testcase classname="tools.test_history_backfill" name="test_id_rechecks_and_participants_share_the_bulk_pacer[rpc0]" file="tools/test_history_backfill.py" line="337" time="0.213" /><testcase classname="tools.test_history_backfill" name="test_id_rechecks_and_participants_share_the_bulk_pacer[rpc1]" file="tools/test_history_backfill.py" line="337" time="0.224" /><testcase classname="tools.test_history_backfill" name="test_id_rechecks_and_participants_share_the_bulk_pacer[rpc2]" file="tools/test_history_backfill.py" line="337" time="0.229" /><testcase classname="tools.test_history_backfill" name="test_concurrent_rpc_waiters_share_pacing_and_server_cooldown[False]" file="tools/test_history_backfill.py" line="367" time="1.724" /><testcase classname="tools.test_history_backfill" name="test_concurrent_rpc_waiters_share_pacing_and_server_cooldown[True]" file="tools/test_history_backfill.py" line="367" time="1.215" /><testcase classname="tools.test_history_backfill" name="test_network_retry_exhaustion_pauses_without_claiming_eof" file="tools/test_history_backfill.py" line="396" time="0.271" /><testcase classname="tools.test_history_backfill" name="test_legacy_cursor_is_reconstructed_from_signed_observations" file="tools/test_history_backfill.py" line="416" time="0.227" /><testcase classname="tools.test_history_backfill" name="test_cancel_closes_takeout_unsuccessfully_and_preserves_observations" file="tools/test_history_backfill.py" line="438" time="0.408" /><testcase classname="tools.test_history_backfill" name="test_admin_final_pass_collects_new_actions_without_duplicates" file="tools/test_history_backfill.py" line="456" time="0.783" /><testcase classname="tools.test_history_backfill" name="test_raw_page_preserves_empty_messages_and_does_not_hide_short_pages" file="tools/test_history_backfill.py" line="480" time="0.001" /><testcase classname="tools.test_history_backfill" name="test_empty_message_advances_cursor_as_unavailable_without_losing_older_text[None]" file="tools/test_history_backfill.py" line="494" time="0.484" /><testcase classname="tools.test_history_backfill" name="test_empty_message_advances_cursor_as_unavailable_without_losing_older_text[peer1]" file="tools/test_history_backfill.py" line="494" time="0.457" /><testcase classname="tools.test_history_backfill" name="test_takeout_media_authorization_loss_pauses_and_retains_queue" file="tools/test_history_backfill.py" line="508" time="0.523" /><testcase classname="tools.test_history_backfill" name="test_cancelled_takeout_marks_pending_files_skipped" file="tools/test_history_backfill.py" line="529" time="0.350" /><testcase classname="tools.test_independent_report_pdf" name="test_signed_selected_pdf_preserves_subject_full_changes_and_private_boundaries[reading_series]" file="tools/test_independent_report_pdf.py" line="57" time="0.985" /><testcase classname="tools.test_independent_report_pdf" name="test_signed_selected_pdf_preserves_subject_full_changes_and_private_boundaries[ledger_margin]" file="tools/test_independent_report_pdf.py" line="57" time="0.999" /><testcase classname="tools.test_independent_report_pdf" name="test_chat_export_uses_native_design_and_keeps_snapshot_semantics[reading_series]" file="tools/test_independent_report_pdf.py" line="104" time="1.482" /><testcase classname="tools.test_independent_report_pdf" name="test_chat_export_uses_native_design_and_keeps_snapshot_semantics[ledger_margin]" file="tools/test_independent_report_pdf.py" line="104" time="0.641" /><testcase classname="tools.test_independent_report_pdf" name="test_bounded_directory_replays_every_event_without_hidden_metadata" file="tools/test_independent_report_pdf.py" line="132" time="0.011" /><testcase classname="tools.test_independent_report_pdf" name="test_minimised_handover_never_restores_original_content_or_operator_analysis[reading_series]" file="tools/test_independent_report_pdf.py" line="143" time="0.968" /><testcase classname="tools.test_independent_report_pdf" name="test_minimised_handover_never_restores_original_content_or_operator_analysis[ledger_margin]" file="tools/test_independent_report_pdf.py" line="143" time="0.879" /><testcase classname="tools.test_independent_report_pdf" name="test_complete_long_comparisons_flow_in_native_pdf[reading_series]" file="tools/test_independent_report_pdf.py" line="167" time="0.599" /><testcase classname="tools.test_independent_report_pdf" name="test_complete_long_comparisons_flow_in_native_pdf[ledger_margin]" file="tools/test_independent_report_pdf.py" line="167" time="1.314" /><testcase classname="tools.test_indicator_limits" name="test_oversized_words_do_not_reach_unbounded_indicator_regexes" file="tools/test_indicator_limits.py" line="9" time="0.023" /><testcase classname="tools.test_indicator_limits" name="test_word_boundaries_preserve_match_offsets_and_the_limit" file="tools/test_indicator_limits.py" line="30" time="0.000" /><testcase classname="tools.test_insights" name="test_replies_hours_deletions_and_presence" file="tools/test_insights.py" line="38" time="0.000" /><testcase classname="tools.test_insights" name="test_deleted_message_outside_the_window_uses_saved_content" file="tools/test_insights.py" line="59" time="0.000" /><testcase classname="tools.test_insights" name="test_collect_reads_a_signed_store" file="tools/test_insights.py" line="65" time="0.277" /><testcase classname="tools.test_installer_checks.InstallerChecksTests" name="test_api_failure_does_not_publish" file="tools/test_installer_checks.py" line="85" time="0.001" /><testcase classname="tools.test_installer_checks.InstallerChecksTests" name="test_exact_revision_passes_and_optional_path_filtered_check_can_be_absent" file="tools/test_installer_checks.py" line="28" time="0.001" /><testcase classname="tools.test_installer_checks.InstallerChecksTests" name="test_missing_required_check_times_out_instead_of_publishing" file="tools/test_installer_checks.py" line="69" time="0.001" /><testcase classname="tools.test_installer_checks.InstallerChecksTests" name="test_newer_failure_or_rerun_never_reuses_an_older_success" file="tools/test_installer_checks.py" line="38" time="0.002" /><testcase classname="tools.test_installer_checks.InstallerChecksTests" name="test_obsolete_build_is_skipped_without_waiting_for_cancelled_checks" file="tools/test_installer_checks.py" line="66" time="0.001" /><testcase classname="tools.test_installer_checks.InstallerChecksTests" name="test_optional_run_must_pass_if_started" file="tools/test_installer_checks.py" line="58" time="0.001" /><testcase classname="tools.test_installer_checks.InstallerChecksTests" name="test_queued_and_in_progress_runs_are_not_passed" file="tools/test_installer_checks.py" line="45" time="0.007" /><testcase classname="tools.test_installer_checks.InstallerChecksTests" name="test_skipped_cancelled_and_failed_checks_block_publication" file="tools/test_installer_checks.py" line="51" time="0.007" /><testcase classname="tools.test_installer_checks.InstallerChecksTests" name="test_wait_rechecks_until_success" file="tools/test_installer_checks.py" line="76" time="0.006" /><testcase classname="tools.test_installer_checks.InstallerChecksTests" name="test_wrong_revision_branch_event_or_repository_cannot_qualify" file="tools/test_installer_checks.py" line="31" time="0.002" /><testcase classname="tools.test_journal_write_failures" name="test_note_counts_logs_and_retains_failures_after_recovery" file="tools/test_journal_write_failures.py" line="27" time="0.285" /><testcase classname="tools.test_journal_write_failures" name="test_failed_transaction_is_counted_without_a_partial_record" file="tools/test_journal_write_failures.py" line="47" time="0.289" /><testcase classname="tools.test_journal_write_failures" name="test_listener_failure_preserves_committed_bytes_and_later_listeners" file="tools/test_journal_write_failures.py" line="62" time="0.801" /><testcase classname="tools.test_journal_write_failures" name="test_journal_failure_sets_health_even_after_observation_stops[True]" file="tools/test_journal_write_failures.py" line="100" time="0.267" /><testcase classname="tools.test_journal_write_failures" name="test_journal_failure_sets_health_even_after_observation_stops[False]" file="tools/test_journal_write_failures.py" line="100" time="0.241" /><testcase classname="tools.test_journal_write_failures" name="test_signed_payload_is_the_stored_and_exported_payload" file="tools/test_journal_write_failures.py" line="121" time="0.396" /><testcase classname="tools.test_jurisdiction_guidance" name="test_default_and_disabled_guidance_preserve_the_existing_assessment" file="tools/test_jurisdiction_guidance.py" line="19" time="0.000" /><testcase classname="tools.test_jurisdiction_guidance" name="test_catalog_routes_keep_sources_local_summary_and_research_status[civil-AU]" file="tools/test_jurisdiction_guidance.py" line="30" time="0.000" /><testcase classname="tools.test_jurisdiction_guidance" name="test_catalog_routes_keep_sources_local_summary_and_research_status[civil-BR]" file="tools/test_jurisdiction_guidance.py" line="30" time="0.000" /><testcase classname="tools.test_jurisdiction_guidance" name="test_catalog_routes_keep_sources_local_summary_and_research_status[civil-CA]" file="tools/test_jurisdiction_guidance.py" line="30" time="0.000" /><testcase classname="tools.test_jurisdiction_guidance" name="test_catalog_routes_keep_sources_local_summary_and_research_status[civil-CN]" file="tools/test_jurisdiction_guidance.py" line="30" time="0.000" /><testcase classname="tools.test_jurisdiction_guidance" name="test_catalog_routes_keep_sources_local_summary_and_research_status[civil-GB-EW]" file="tools/test_jurisdiction_guidance.py" line="30" time="0.000" /><testcase classname="tools.test_jurisdiction_guidance" name="test_catalog_routes_keep_sources_local_summary_and_research_status[civil-FR]" file="tools/test_jurisdiction_guidance.py" line="30" time="0.000" /><testcase classname="tools.test_jurisdiction_guidance" name="test_catalog_routes_keep_sources_local_summary_and_research_status[civil-DE]" file="tools/test_jurisdiction_guidance.py" line="30" time="0.000" /><testcase classname="tools.test_jurisdiction_guidance" name="test_catalog_routes_keep_sources_local_summary_and_research_status[civil-IN]" file="tools/test_jurisdiction_guidance.py" line="30" time="0.001" /><testcase classname="tools.test_jurisdiction_guidance" name="test_catalog_routes_keep_sources_local_summary_and_research_status[civil-ID]" file="tools/test_jurisdiction_guidance.py" line="30" time="0.001" /><testcase classname="tools.test_jurisdiction_guidance" name="test_catalog_routes_keep_sources_local_summary_and_research_status[civil-IR]" file="tools/test_jurisdiction_guidance.py" line="30" time="0.001" /><testcase classname="tools.test_jurisdiction_guidance" name="test_catalog_routes_keep_sources_local_summary_and_research_status[civil-IT]" file="tools/test_jurisdiction_guidance.py" line="30" time="0.001" /><testcase classname="tools.test_jurisdiction_guidance" name="test_catalog_routes_keep_sources_local_summary_and_research_status[civil-MY]" file="tools/test_jurisdiction_guidance.py" line="30" time="0.001" /><testcase classname="tools.test_jurisdiction_guidance" name="test_catalog_routes_keep_sources_local_summary_and_research_status[civil-MX]" file="tools/test_jurisdiction_guidance.py" line="30" time="0.001" /><testcase classname="tools.test_jurisdiction_guidance" name="test_catalog_routes_keep_sources_local_summary_and_research_status[civil-PK]" file="tools/test_jurisdiction_guidance.py" line="30" time="0.001" /><testcase classname="tools.test_jurisdiction_guidance" name="test_catalog_routes_keep_sources_local_summary_and_research_status[civil-PH]" file="tools/test_jurisdiction_guidance.py" line="30" time="0.001" /><testcase classname="tools.test_jurisdiction_guidance" name="test_catalog_routes_keep_sources_local_summary_and_research_status[civil-PT]" file="tools/test_jurisdiction_guidance.py" line="30" time="0.001" /><testcase classname="tools.test_jurisdiction_guidance" name="test_catalog_routes_keep_sources_local_summary_and_research_status[civil-RU]" file="tools/test_jurisdiction_guidance.py" line="30" time="0.001" /><testcase classname="tools.test_jurisdiction_guidance" name="test_catalog_routes_keep_sources_local_summary_and_research_status[civil-SA]" file="tools/test_jurisdiction_guidance.py" line="30" time="0.001" /><testcase classname="tools.test_jurisdiction_guidance" name="test_catalog_routes_keep_sources_local_summary_and_research_status[civil-SG]" file="tools/test_jurisdiction_guidance.py" line="30" time="0.001" /><testcase classname="tools.test_jurisdiction_guidance" name="test_catalog_routes_keep_sources_local_summary_and_research_status[civil-ES]" file="tools/test_jurisdiction_guidance.py" line="30" time="0.001" /><testcase classname="tools.test_jurisdiction_guidance" name="test_catalog_routes_keep_sources_local_summary_and_research_status[civil-TR]" file="tools/test_jurisdiction_guidance.py" line="30" time="0.001" /><testcase classname="tools.test_jurisdiction_guidance" name="test_catalog_routes_keep_sources_local_summary_and_research_status[civil-UA]" file="tools/test_jurisdiction_guidance.py" line="30" time="0.001" /><testcase classname="tools.test_jurisdiction_guidance" name="test_catalog_routes_keep_sources_local_summary_and_research_status[civil-AE]" file="tools/test_jurisdiction_guidance.py" line="30" time="0.001" /><testcase classname="tools.test_jurisdiction_guidance" name="test_catalog_routes_keep_sources_local_summary_and_research_status[civil-US]" file="tools/test_jurisdiction_guidance.py" line="30" time="0.001" /><testcase classname="tools.test_jurisdiction_guidance" name="test_catalog_routes_keep_sources_local_summary_and_research_status[civil-VN]" file="tools/test_jurisdiction_guidance.py" line="30" time="0.001" /><testcase classname="tools.test_jurisdiction_guidance" name="test_catalog_routes_keep_sources_local_summary_and_research_status[criminal-AU]" file="tools/test_jurisdiction_guidance.py" line="30" time="0.001" /><testcase classname="tools.test_jurisdiction_guidance" name="test_catalog_routes_keep_sources_local_summary_and_research_status[criminal-BR]" file="tools/test_jurisdiction_guidance.py" line="30" time="0.001" /><testcase classname="tools.test_jurisdiction_guidance" name="test_catalog_routes_keep_sources_local_summary_and_research_status[criminal-CA]" file="tools/test_jurisdiction_guidance.py" line="30" time="0.001" /><testcase classname="tools.test_jurisdiction_guidance" name="test_catalog_routes_keep_sources_local_summary_and_research_status[criminal-CN]" file="tools/test_jurisdiction_guidance.py" line="30" time="0.001" /><testcase classname="tools.test_jurisdiction_guidance" name="test_catalog_routes_keep_sources_local_summary_and_research_status[criminal-GB-EW]" file="tools/test_jurisdiction_guidance.py" line="30" time="0.001" /><testcase classname="tools.test_jurisdiction_guidance" name="test_catalog_routes_keep_sources_local_summary_and_research_status[criminal-FR]" file="tools/test_jurisdiction_guidance.py" line="30" time="0.001" /><testcase classname="tools.test_jurisdiction_guidance" name="test_catalog_routes_keep_sources_local_summary_and_research_status[criminal-DE]" file="tools/test_jurisdiction_guidance.py" line="30" time="0.001" /><testcase classname="tools.test_jurisdiction_guidance" name="test_catalog_routes_keep_sources_local_summary_and_research_status[criminal-IN]" file="tools/test_jurisdiction_guidance.py" line="30" time="0.001" /><testcase classname="tools.test_jurisdiction_guidance" name="test_catalog_routes_keep_sources_local_summary_and_research_status[criminal-ID]" file="tools/test_jurisdiction_guidance.py" line="30" time="0.001" /><testcase classname="tools.test_jurisdiction_guidance" name="test_catalog_routes_keep_sources_local_summary_and_research_status[criminal-IR]" file="tools/test_jurisdiction_guidance.py" line="30" time="0.001" /><testcase classname="tools.test_jurisdiction_guidance" name="test_catalog_routes_keep_sources_local_summary_and_research_status[criminal-IT]" file="tools/test_jurisdiction_guidance.py" line="30" time="0.001" /><testcase classname="tools.test_jurisdiction_guidance" name="test_catalog_routes_keep_sources_local_summary_and_research_status[criminal-MY]" file="tools/test_jurisdiction_guidance.py" line="30" time="0.000" /><testcase classname="tools.test_jurisdiction_guidance" name="test_catalog_routes_keep_sources_local_summary_and_research_status[criminal-MX]" file="tools/test_jurisdiction_guidance.py" line="30" time="0.000" /><testcase classname="tools.test_jurisdiction_guidance" name="test_catalog_routes_keep_sources_local_summary_and_research_status[criminal-PK]" file="tools/test_jurisdiction_guidance.py" line="30" time="0.000" /><testcase classname="tools.test_jurisdiction_guidance" name="test_catalog_routes_keep_sources_local_summary_and_research_status[criminal-PH]" file="tools/test_jurisdiction_guidance.py" line="30" time="0.000" /><testcase classname="tools.test_jurisdiction_guidance" name="test_catalog_routes_keep_sources_local_summary_and_research_status[criminal-PT]" file="tools/test_jurisdiction_guidance.py" line="30" time="0.000" /><testcase classname="tools.test_jurisdiction_guidance" name="test_catalog_routes_keep_sources_local_summary_and_research_status[criminal-RU]" file="tools/test_jurisdiction_guidance.py" line="30" time="0.000" /><testcase classname="tools.test_jurisdiction_guidance" name="test_catalog_routes_keep_sources_local_summary_and_research_status[criminal-SA]" file="tools/test_jurisdiction_guidance.py" line="30" time="0.000" /><testcase classname="tools.test_jurisdiction_guidance" name="test_catalog_routes_keep_sources_local_summary_and_research_status[criminal-SG]" file="tools/test_jurisdiction_guidance.py" line="30" time="0.000" /><testcase classname="tools.test_jurisdiction_guidance" name="test_catalog_routes_keep_sources_local_summary_and_research_status[criminal-ES]" file="tools/test_jurisdiction_guidance.py" line="30" time="0.000" /><testcase classname="tools.test_jurisdiction_guidance" name="test_catalog_routes_keep_sources_local_summary_and_research_status[criminal-TR]" file="tools/test_jurisdiction_guidance.py" line="30" time="0.000" /><testcase classname="tools.test_jurisdiction_guidance" name="test_catalog_routes_keep_sources_local_summary_and_research_status[criminal-UA]" file="tools/test_jurisdiction_guidance.py" line="30" time="0.000" /><testcase classname="tools.test_jurisdiction_guidance" name="test_catalog_routes_keep_sources_local_summary_and_research_status[criminal-AE]" file="tools/test_jurisdiction_guidance.py" line="30" time="0.000" /><testcase classname="tools.test_jurisdiction_guidance" name="test_catalog_routes_keep_sources_local_summary_and_research_status[criminal-US]" file="tools/test_jurisdiction_guidance.py" line="30" time="0.000" /><testcase classname="tools.test_jurisdiction_guidance" name="test_catalog_routes_keep_sources_local_summary_and_research_status[criminal-VN]" file="tools/test_jurisdiction_guidance.py" line="30" time="0.000" /><testcase classname="tools.test_jurisdiction_guidance" name="test_choices_do_not_upgrade_facts_or_claim_safeguards_were_used" file="tools/test_jurisdiction_guidance.py" line="45" time="0.000"><failure message="assert 'does not mean a measure was used or verified' in '&lt;section class=&quot;card panel case-assessment&quot; id=&quot;jurisdiction-guidance&quot; lang=&quot;en&quot; dir=&quot;ltr&quot;&gt;&lt;h2&gt;Jurisdiction guidance&lt;...ed by a separate party takes the host and hypervisor out of the operator&amp;#x27;s control.&lt;/p&gt;&lt;/article&gt;&lt;/div&gt;&lt;/section&gt;'&#10;[+2 more lines; full report in element text]">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
&gt;       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 '&lt;section class="card panel case-assessment" id="jurisdiction-guidance" lang="en" dir="ltr"&gt;&lt;h2&gt;Jurisdiction guidance&lt;...ed by a separate party takes the host and hypervisor out of the operator&amp;#x27;s control.&lt;/p&gt;&lt;/article&gt;&lt;/div&gt;&lt;/section&gt;'
E        +  where '&lt;section class="card panel case-assessment" id="jurisdiction-guidance" lang="en" dir="ltr"&gt;&lt;h2&gt;Jurisdiction guidance&lt;...ed by a separate party takes the host and hypervisor out of the operator&amp;#x27;s control.&lt;/p&gt;&lt;/article&gt;&lt;/div&gt;&lt;/section&gt;' = &lt;function html at 0x747f92271a80&gt;({'format': 'tgwitness-jurisdiction-guidance-v1', 'language': 'en', 'catalog_version': '2026-11-06.1', 'catalog_sha256': 'd77d49d1d9f26dcf70906ff42a13b8e36d463d78d3dccbee82884477b96fe1d2', ...})
E        +    where &lt;function html at 0x747f92271a80&gt; = guide.html

tools/test_jurisdiction_guidance.py:55: AssertionError</failure></testcase><testcase classname="tools.test_jurisdiction_guidance" name="test_next_steps_use_the_exact_export_findings_without_mutating_them" file="tools/test_jurisdiction_guidance.py" line="60" time="0.000" /><testcase classname="tools.test_jurisdiction_guidance" name="test_existing_receipts_and_partial_time_bounds_get_different_actions" file="tools/test_jurisdiction_guidance.py" line="77" time="0.000" /><testcase classname="tools.test_jurisdiction_guidance" name="test_present_quotes_need_verification_and_preview_does_not_invent_findings" file="tools/test_jurisdiction_guidance.py" line="95" time="0.000" /><testcase classname="tools.test_jurisdiction_guidance" name="test_saved_settings_are_not_layout_or_implicit_sharing_context" file="tools/test_jurisdiction_guidance.py" line="107" time="0.235" /><testcase classname="tools.test_jurisdiction_guidance" name="test_api_permissions_workspace_isolation_and_export_inheritance" file="tools/test_jurisdiction_guidance.py" line="129" time="1.453" /><testcase classname="tools.test_jurisdiction_guidance" name="test_local_pdf_summary_never_silently_loses_its_script" file="tools/test_jurisdiction_guidance.py" line="157" time="0.284" /><testcase classname="tools.test_jurisdiction_guidance" name="test_signed_exports_share_guidance_across_formats_and_designs[classic]" file="tools/test_jurisdiction_guidance.py" line="173" time="0.977" /><testcase classname="tools.test_jurisdiction_guidance" name="test_signed_exports_share_guidance_across_formats_and_designs[quire]" file="tools/test_jurisdiction_guidance.py" line="173" time="0.969" /><testcase classname="tools.test_jurisdiction_guidance" name="test_signed_exports_share_guidance_across_formats_and_designs[meridian]" file="tools/test_jurisdiction_guidance.py" line="173" time="1.934" /><testcase classname="tools.test_jurisdiction_guidance" name="test_signed_exports_share_guidance_across_formats_and_designs[atlas]" file="tools/test_jurisdiction_guidance.py" line="173" time="1.050" /><testcase classname="tools.test_jurisdiction_guidance" name="test_signed_exports_share_guidance_across_formats_and_designs[ledger]" file="tools/test_jurisdiction_guidance.py" line="173" time="1.054" /><testcase classname="tools.test_jurisdiction_guidance" name="test_signed_exports_share_guidance_across_formats_and_designs[horizon]" file="tools/test_jurisdiction_guidance.py" line="173" time="1.000" /><testcase classname="tools.test_jurisdiction_guidance" name="test_signed_exports_share_guidance_across_formats_and_designs[reading_series]" file="tools/test_jurisdiction_guidance.py" line="173" time="1.098" /><testcase classname="tools.test_jurisdiction_guidance" name="test_signed_exports_share_guidance_across_formats_and_designs[ledger_margin]" file="tools/test_jurisdiction_guidance.py" line="173" time="1.959" /><testcase classname="tools.test_jurisdiction_guidance" name="test_signed_exports_share_guidance_across_formats_and_designs[profile_overview]" file="tools/test_jurisdiction_guidance.py" line="173" time="1.011" /><testcase classname="tools.test_lookup_backoff" name="test_lookup_preserves_telegram_wait[FloodWaitError]" file="tools/test_lookup_backoff.py" line="16" time="0.001" /><testcase classname="tools.test_lookup_backoff" name="test_lookup_preserves_telegram_wait[FloodPremiumWaitError]" file="tools/test_lookup_backoff.py" line="16" time="0.001" /><testcase classname="tools.test_lookup_backoff" name="test_unknown_peer_still_returns_no_entity" file="tools/test_lookup_backoff.py" line="27" time="0.001" /><testcase classname="tools.test_lookup_backoff" name="test_new_chat_intake_requeues_lookup_after_wait[FloodWaitError]" file="tools/test_lookup_backoff.py" line="32" time="0.243" /><testcase classname="tools.test_lookup_backoff" name="test_new_chat_intake_requeues_lookup_after_wait[FloodPremiumWaitError]" file="tools/test_lookup_backoff.py" line="32" time="0.241" /><testcase classname="tools.test_media_job_states" name="test_saved_state_requires_hash_and_storage_before_finish" file="tools/test_media_job_states.py" line="22" time="0.000" /><testcase classname="tools.test_media_job_states" name="test_failed_journal_commit_does_not_finalize_in_memory_attempt" file="tools/test_media_job_states.py" line="40" time="0.000" /><testcase classname="tools.test_media_job_states" name="test_retry_policy_keeps_attempt_limit_backoff_and_reason[exception0-1-5-retry-10]" file="tools/test_media_job_states.py" line="53" time="0.000" /><testcase classname="tools.test_media_job_states" name="test_retry_policy_keeps_attempt_limit_backoff_and_reason[exception1-5-5-failed-0]" file="tools/test_media_job_states.py" line="53" time="0.000" /><testcase classname="tools.test_media_job_states" name="test_retry_policy_keeps_attempt_limit_backoff_and_reason[exception2-4-5-retry-80]" file="tools/test_media_job_states.py" line="53" time="0.000" /><testcase classname="tools.test_media_job_states" name="test_retry_policy_keeps_attempt_limit_backoff_and_reason[exception3-30-100-retry-300]" file="tools/test_media_job_states.py" line="53" time="0.000" /><testcase classname="tools.test_media_job_states" name="test_retry_policy_keeps_attempt_limit_backoff_and_reason[exception4-1-5-failed-0]" file="tools/test_media_job_states.py" line="53" time="0.000" /><testcase classname="tools.test_media_job_states" name="test_retry_policy_keeps_attempt_limit_backoff_and_reason[exception5-1-5-failed-0]" file="tools/test_media_job_states.py" line="53" time="0.000" /><testcase classname="tools.test_media_job_states" name="test_retry_policy_keeps_attempt_limit_backoff_and_reason[exception6-1-0-failed-0]" file="tools/test_media_job_states.py" line="53" time="0.000" /><testcase classname="tools.test_media_job_states" name="test_changed_descriptor_cannot_replace_the_signed_observation" file="tools/test_media_job_states.py" line="70" time="0.238" /><testcase classname="tools.test_media_job_states" name="test_hash_only_outcome_never_enters_byte_download[True]" file="tools/test_media_job_states.py" line="85" time="0.241" /><testcase classname="tools.test_media_job_states" name="test_hash_only_outcome_never_enters_byte_download[False]" file="tools/test_media_job_states.py" line="85" time="0.250" /><testcase classname="tools.test_media_job_states" name="test_cancellation_retains_job_then_resumes_without_rewriting_observation" file="tools/test_media_job_states.py" line="112" time="0.257" /><testcase classname="tools.test_media_job_states" name="test_recovered_claim_resumes_existing_durable_job" file="tools/test_media_job_states.py" line="146" time="0.235" /><testcase classname="tools.test_media_job_states" name="test_download_faults_keep_original_retry_and_failure_semantics[network]" file="tools/test_media_job_states.py" line="165" time="0.226" /><testcase classname="tools.test_media_job_states" name="test_download_faults_keep_original_retry_and_failure_semantics[exhausted]" file="tools/test_media_job_states.py" line="165" time="0.222" /><testcase classname="tools.test_media_job_states" name="test_download_faults_keep_original_retry_and_failure_semantics[flood]" file="tools/test_media_job_states.py" line="165" time="0.230" /><testcase classname="tools.test_media_job_states" name="test_download_faults_keep_original_retry_and_failure_semantics[authorization]" file="tools/test_media_job_states.py" line="165" time="0.234" /><testcase classname="tools.test_media_job_states" name="test_download_faults_keep_original_retry_and_failure_semantics[takeout]" file="tools/test_media_job_states.py" line="165" time="0.227" /><testcase classname="tools.test_media_job_states" name="test_download_faults_keep_original_retry_and_failure_semantics[size]" file="tools/test_media_job_states.py" line="165" time="0.224" /><testcase classname="tools.test_media_job_states" name="test_download_faults_keep_original_retry_and_failure_semantics[disk]" file="tools/test_media_job_states.py" line="165" time="0.238" /><testcase classname="tools.test_media_job_states" name="test_expired_reference_retries_only_the_same_observed_attachment" file="tools/test_media_job_states.py" line="219" time="0.243" /><testcase classname="tools.test_messages_first_live_media" name="test_live_jobs_are_claimed_while_history_jobs_wait_for_their_run" file="tools/test_messages_first_live_media.py" line="25" time="0.213" /><testcase classname="tools.test_messages_first_live_media" name="test_exclusion_is_limited_to_the_named_run" file="tools/test_messages_first_live_media.py" line="36" time="0.204" /><testcase classname="tools.test_messages_first_live_media" name="test_history_worker_still_claims_only_its_own_jobs" file="tools/test_messages_first_live_media.py" line="43" time="0.207" /><testcase classname="tools.test_metrics" name="test_registry_lists_versioned_processors_with_parameters" file="tools/test_metrics.py" line="24" time="0.000" /><testcase classname="tools.test_metrics" name="test_first_time_posters_flag_injection_after_warm_up" file="tools/test_metrics.py" line="51" time="0.001" /><testcase classname="tools.test_metrics" name="test_service_share_counts_distinct_numbers" file="tools/test_metrics.py" line="60" time="0.000" /><testcase classname="tools.test_metrics" name="test_history_service_messages_are_classified_without_duplicate_service_record" file="tools/test_metrics.py" line="67" time="0.000" /><testcase classname="tools.test_metrics" name="test_posters_warmup_uses_calendar_days" file="tools/test_metrics.py" line="76" time="0.000" /><testcase classname="tools.test_metrics" name="test_joins_and_departures_per_month_count_each_change_once" file="tools/test_metrics.py" line="89" time="0.000" /><testcase classname="tools.test_metrics" name="test_pins_unpins_and_snapshot_changes_per_month" file="tools/test_metrics.py" line="98" time="0.000" /><testcase classname="tools.test_metrics" name="test_reports_list_processors_and_follow_parameters" file="tools/test_metrics.py" line="109" time="2.896" /><testcase classname="tools.test_mtproto_forensics" name="test_ige_matches_telethon_in_both_directions" file="tools/test_mtproto_forensics.py" line="68" time="0.001" /><testcase classname="tools.test_mtproto_forensics" name="test_kdf_matches_independent_telethon_implementation[True]" file="tools/test_mtproto_forensics.py" line="76" time="0.001" /><testcase classname="tools.test_mtproto_forensics" name="test_kdf_matches_independent_telethon_implementation[False]" file="tools/test_mtproto_forensics.py" line="76" time="0.000" /><testcase classname="tools.test_mtproto_forensics" name="test_frame_decrypts_independent_telethon_vector[True]" file="tools/test_mtproto_forensics.py" line="83" time="0.000" /><testcase classname="tools.test_mtproto_forensics" name="test_frame_decrypts_independent_telethon_vector[False]" file="tools/test_mtproto_forensics.py" line="83" time="0.000" /><testcase classname="tools.test_mtproto_forensics" name="test_decrypts_frame_emitted_by_telethon_state" file="tools/test_mtproto_forensics.py" line="99" time="0.000" /><testcase classname="tools.test_mtproto_forensics" name="test_authenticated_but_invalid_headers_and_padding_are_rejected[options0]" file="tools/test_mtproto_forensics.py" line="108" time="0.000" /><testcase classname="tools.test_mtproto_forensics" name="test_authenticated_but_invalid_headers_and_padding_are_rejected[options1]" file="tools/test_mtproto_forensics.py" line="108" time="0.000" /><testcase classname="tools.test_mtproto_forensics" name="test_authenticated_but_invalid_headers_and_padding_are_rejected[options2]" file="tools/test_mtproto_forensics.py" line="108" time="0.000" /><testcase classname="tools.test_mtproto_forensics" name="test_authenticated_but_invalid_headers_and_padding_are_rejected[options3]" file="tools/test_mtproto_forensics.py" line="108" time="0.000" /><testcase classname="tools.test_mtproto_forensics" name="test_authenticated_but_invalid_headers_and_padding_are_rejected[options4]" file="tools/test_mtproto_forensics.py" line="108" time="0.000" /><testcase classname="tools.test_mtproto_forensics" name="test_authenticated_but_invalid_headers_and_padding_are_rejected[options5]" file="tools/test_mtproto_forensics.py" line="108" time="0.000" /><testcase classname="tools.test_mtproto_forensics" name="test_authenticated_but_invalid_headers_and_padding_are_rejected[options6]" file="tools/test_mtproto_forensics.py" line="108" time="0.000" /><testcase classname="tools.test_mtproto_forensics" name="test_authenticated_but_invalid_headers_and_padding_are_rejected[options7]" file="tools/test_mtproto_forensics.py" line="108" time="0.000" /><testcase classname="tools.test_mtproto_forensics" name="test_authenticated_but_invalid_headers_and_padding_are_rejected[options8]" file="tools/test_mtproto_forensics.py" line="108" time="0.001" /><testcase classname="tools.test_mtproto_forensics" name="test_wrong_direction_fails_integrity[True]" file="tools/test_mtproto_forensics.py" line="119" time="0.000" /><testcase classname="tools.test_mtproto_forensics" name="test_wrong_direction_fails_integrity[False]" file="tools/test_mtproto_forensics.py" line="119" time="0.000" /><testcase classname="tools.test_mtproto_forensics" name="test_foreign_key_and_tampered_ciphertext_are_rejected" file="tools/test_mtproto_forensics.py" line="126" time="0.000" /><testcase classname="tools.test_mtproto_forensics" name="test_truncated_envelopes_fail_closed[0]" file="tools/test_mtproto_forensics.py" line="136" time="0.000" /><testcase classname="tools.test_mtproto_forensics" name="test_truncated_envelopes_fail_closed[8]" file="tools/test_mtproto_forensics.py" line="136" time="0.000" /><testcase classname="tools.test_mtproto_forensics" name="test_truncated_envelopes_fail_closed[24]" file="tools/test_mtproto_forensics.py" line="136" time="0.000" /><testcase classname="tools.test_mtproto_forensics" name="test_truncated_envelopes_fail_closed[40]" file="tools/test_mtproto_forensics.py" line="136" time="0.000" /><testcase classname="tools.test_mtproto_forensics" name="test_truncated_envelopes_fail_closed[71]" file="tools/test_mtproto_forensics.py" line="136" time="0.000" /><testcase classname="tools.test_mtproto_forensics" name="test_truncated_envelopes_fail_closed[-1]" file="tools/test_mtproto_forensics.py" line="136" time="0.000" /><testcase classname="tools.test_mtproto_forensics" name="test_rejects_invalid_key_sizes_and_unaligned_aes_input" file="tools/test_mtproto_forensics.py" line="142" time="0.000" /><testcase classname="tools.test_mtproto_forensics" name="test_offline_frame_size_limit" file="tools/test_mtproto_forensics.py" line="153" time="0.000" /><testcase classname="tools.test_mtproto_forensics" name="test_extract_auth_key_opens_session_read_only" file="tools/test_mtproto_forensics.py" line="160" time="0.045" /><testcase classname="tools.test_mtproto_forensics" name="test_extract_auth_key_reports_missing_file" file="tools/test_mtproto_forensics.py" line="167" time="0.001" /><testcase classname="tools.test_mtproto_forensics" name="test_extract_auth_key_rejects_wrong_length" file="tools/test_mtproto_forensics.py" line="172" time="0.033" /><testcase classname="tools.test_mtproto_forensics" name="test_identifier_alone_cannot_validate_fictional_message_content" file="tools/test_mtproto_forensics.py" line="177" time="0.000" /><testcase classname="tools.test_mtproto_forensics" name="test_digest_match_is_separate_from_original_event_and_origin" file="tools/test_mtproto_forensics.py" line="188" time="0.000" /><testcase classname="tools.test_mtproto_forensics" name="test_digest_cannot_override_conflicting_message_id" file="tools/test_mtproto_forensics.py" line="201" time="0.000" /><testcase classname="tools.test_mtproto_forensics" name="test_invalid_or_absent_digest_does_not_match[invalid]" file="tools/test_mtproto_forensics.py" line="209" time="0.000" /><testcase classname="tools.test_mtproto_forensics" name="test_invalid_or_absent_digest_does_not_match[0000000000000000000000000000000000000000000000000000000000000000]" file="tools/test_mtproto_forensics.py" line="209" time="0.000" /><testcase classname="tools.test_mtproto_forensics" name="test_invalid_or_absent_digest_does_not_match[7]" file="tools/test_mtproto_forensics.py" line="209" time="0.000" /><testcase classname="tools.test_mtproto_forensics" name="test_invalid_or_absent_digest_does_not_match[digest3]" file="tools/test_mtproto_forensics.py" line="209" time="0.000" /><testcase classname="tools.test_mtproto_forensics" name="test_unanchored_events_remain_unjudged" file="tools/test_mtproto_forensics.py" line="216" time="0.000" /><testcase classname="tools.test_mtproto_forensics" name="test_invalid_frames_cannot_be_silently_ignored[]" file="tools/test_mtproto_forensics.py" line="223" time="0.000" /><testcase classname="tools.test_mtproto_forensics" name="test_invalid_frames_cannot_be_silently_ignored[truncated]" file="tools/test_mtproto_forensics.py" line="223" time="0.000" /><testcase classname="tools.test_mtproto_forensics" name="test_coalesced_complete_frames_must_be_split_before_decryption" file="tools/test_mtproto_forensics.py" line="230" time="0.000" /><testcase classname="tools.test_mtproto_forensics" name="test_pcap_import_is_rejected_before_any_session_is_read" file="tools/test_mtproto_forensics.py" line="236" time="0.000" /><testcase classname="tools.test_mtproto_forensics" name="test_anchor_by_raw_matches_only_exact_bytes" file="tools/test_mtproto_forensics.py" line="243" time="0.000" /><testcase classname="tools.test_mtproto_forensics" name="test_raw_anchors_reject_invalid_lengths[0]" file="tools/test_mtproto_forensics.py" line="254" time="0.000" /><testcase classname="tools.test_mtproto_forensics" name="test_raw_anchors_reject_invalid_lengths[-1]" file="tools/test_mtproto_forensics.py" line="254" time="0.000" /><testcase classname="tools.test_mtproto_forensics" name="test_raw_anchors_reject_invalid_lengths[True]" file="tools/test_mtproto_forensics.py" line="254" time="0.000" /><testcase classname="tools.test_mtproto_forensics" name="test_raw_anchors_reject_invalid_lengths[4]" file="tools/test_mtproto_forensics.py" line="254" time="0.000" /><testcase classname="tools.test_mtproto_forensics" name="test_raw_anchor_scan_is_bounded" file="tools/test_mtproto_forensics.py" line="260" time="0.000" /><testcase classname="tools.test_mtproto_forensics" name="test_peer_settings_flag_is_an_observation_not_contact_import" file="tools/test_mtproto_forensics.py" line="267" time="0.000" /><testcase classname="tools.test_mtproto_forensics" name="test_outbox_read_watermark_does_not_identify_a_person" file="tools/test_mtproto_forensics.py" line="281" time="0.000"><failure message="AssertionError: assert 'does not identify' in 'Observed outgoing read watermark.'">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
&gt;       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</failure></testcase><testcase classname="tools.test_mtproto_forensics" name="test_disabling_raw_updates_after_registration_stops_all_journaling" file="tools/test_mtproto_forensics.py" line="300" time="0.001" /><testcase classname="tools.test_mtproto_forensics" name="test_update_digest_uses_exact_bytes_and_preserves_zero_time" file="tools/test_mtproto_forensics.py" line="338" time="0.000" /><testcase classname="tools.test_mtproto_forensics" name="test_http_observation_ignores_forwarding_claims_and_does_not_attribute_identity" file="tools/test_mtproto_forensics.py" line="347" time="0.000" /><testcase classname="tools.test_mtproto_forensics" name="test_canary_unknown_token_is_ignored" file="tools/test_mtproto_forensics.py" line="365" time="0.000" /><testcase classname="tools.test_mtproto_forensics" name="test_temporal_correlation_never_establishes_identity" file="tools/test_mtproto_forensics.py" line="370" time="0.000" /><testcase classname="tools.test_mtproto_forensics" name="test_framing_splits_coalesced_packets[intermediate-frame_intermediate]" file="tools/test_mtproto_forensics.py" line="377" time="0.000" /><testcase classname="tools.test_mtproto_forensics" name="test_framing_splits_coalesced_packets[abridged-frame_abridged]" file="tools/test_mtproto_forensics.py" line="377" time="0.000" /><testcase classname="tools.test_mtproto_forensics" name="test_truncated_and_invalid_transport_framing_fails_closed[intermediate-\x01]" file="tools/test_mtproto_forensics.py" line="386" time="0.000" /><testcase classname="tools.test_mtproto_forensics" name="test_truncated_and_invalid_transport_framing_fails_closed[intermediate-\x04\x00\x00\x00ab]" file="tools/test_mtproto_forensics.py" line="386" time="0.000" /><testcase classname="tools.test_mtproto_forensics" name="test_truncated_and_invalid_transport_framing_fails_closed[intermediate-\x00\x00\x00\x00]" file="tools/test_mtproto_forensics.py" line="386" time="0.000" /><testcase classname="tools.test_mtproto_forensics" name="test_truncated_and_invalid_transport_framing_fails_closed[abridged-\x00]" file="tools/test_mtproto_forensics.py" line="386" time="0.000" /><testcase classname="tools.test_mtproto_forensics" name="test_truncated_and_invalid_transport_framing_fails_closed[abridged-\x80]" file="tools/test_mtproto_forensics.py" line="386" time="0.000" /><testcase classname="tools.test_mtproto_forensics" name="test_truncated_and_invalid_transport_framing_fails_closed[abridged-\x7f\x01\x00]" file="tools/test_mtproto_forensics.py" line="386" time="0.000" /><testcase classname="tools.test_mtproto_forensics" name="test_truncated_and_invalid_transport_framing_fails_closed[abridged-\x7f\x01\x00\x00]" file="tools/test_mtproto_forensics.py" line="386" time="0.000" /><testcase classname="tools.test_mtproto_forensics" name="test_truncated_and_invalid_transport_framing_fails_closed[abridged-\x02aaaa]" file="tools/test_mtproto_forensics.py" line="386" time="0.000" /><testcase classname="tools.test_mtproto_forensics" name="test_truncated_and_invalid_transport_framing_fails_closed[full-\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01]" file="tools/test_mtproto_forensics.py" line="386" time="0.000" /><testcase classname="tools.test_mtproto_forensics" name="test_truncated_and_invalid_transport_framing_fails_closed[full-\x10\x00\x00\x00\x00\x00\x00\x00data\xec\x07z\xfb\x01]" file="tools/test_mtproto_forensics.py" line="386" time="0.000" /><testcase classname="tools.test_mtproto_forensics" name="test_truncated_and_invalid_transport_framing_fails_closed[intermediate-\x04\x00\x00\x00data\x01]" file="tools/test_mtproto_forensics.py" line="386" time="0.000" /><testcase classname="tools.test_mtproto_forensics" name="test_full_transport_validates_crc_and_sequence" file="tools/test_mtproto_forensics.py" line="403" time="0.000" /><testcase classname="tools.test_mtproto_forensics" name="test_obfuscation_matches_independent_telethon_stream[True]" file="tools/test_mtproto_forensics.py" line="414" time="0.000" /><testcase classname="tools.test_mtproto_forensics" name="test_obfuscation_matches_independent_telethon_stream[False]" file="tools/test_mtproto_forensics.py" line="414" time="0.000" /><testcase classname="tools.test_mtproto_forensics" name="test_padded_transport_removes_only_transport_padding[0]" file="tools/test_mtproto_forensics.py" line="427" time="0.000" /><testcase classname="tools.test_mtproto_forensics" name="test_padded_transport_removes_only_transport_padding[1]" file="tools/test_mtproto_forensics.py" line="427" time="0.000" /><testcase classname="tools.test_mtproto_forensics" name="test_padded_transport_removes_only_transport_padding[2]" file="tools/test_mtproto_forensics.py" line="427" time="0.000" /><testcase classname="tools.test_mtproto_forensics" name="test_padded_transport_removes_only_transport_padding[3]" file="tools/test_mtproto_forensics.py" line="427" time="0.000" /><testcase classname="tools.test_mtproto_forensics" name="test_padded_transport_removes_only_transport_padding[4]" file="tools/test_mtproto_forensics.py" line="427" time="0.000" /><testcase classname="tools.test_mtproto_forensics" name="test_padded_transport_removes_only_transport_padding[5]" file="tools/test_mtproto_forensics.py" line="427" time="0.000" /><testcase classname="tools.test_mtproto_forensics" name="test_padded_transport_removes_only_transport_padding[6]" file="tools/test_mtproto_forensics.py" line="427" time="0.000" /><testcase classname="tools.test_mtproto_forensics" name="test_padded_transport_removes_only_transport_padding[7]" file="tools/test_mtproto_forensics.py" line="427" time="0.000" /><testcase classname="tools.test_mtproto_forensics" name="test_padded_transport_removes_only_transport_padding[8]" file="tools/test_mtproto_forensics.py" line="427" time="0.000" /><testcase classname="tools.test_mtproto_forensics" name="test_padded_transport_removes_only_transport_padding[9]" file="tools/test_mtproto_forensics.py" line="427" time="0.000" /><testcase classname="tools.test_mtproto_forensics" name="test_padded_transport_removes_only_transport_padding[10]" file="tools/test_mtproto_forensics.py" line="427" time="0.000" /><testcase classname="tools.test_mtproto_forensics" name="test_padded_transport_removes_only_transport_padding[11]" file="tools/test_mtproto_forensics.py" line="427" time="0.001" /><testcase classname="tools.test_mtproto_forensics" name="test_padded_transport_removes_only_transport_padding[12]" file="tools/test_mtproto_forensics.py" line="427" time="0.000" /><testcase classname="tools.test_mtproto_forensics" name="test_padded_transport_removes_only_transport_padding[13]" file="tools/test_mtproto_forensics.py" line="427" time="0.000" /><testcase classname="tools.test_mtproto_forensics" name="test_padded_transport_removes_only_transport_padding[14]" file="tools/test_mtproto_forensics.py" line="427" time="0.000" /><testcase classname="tools.test_mtproto_forensics" name="test_padded_transport_removes_only_transport_padding[15]" file="tools/test_mtproto_forensics.py" line="427" time="0.000" /><testcase classname="tools.test_mtproto_forensics" name="test_truncated_padded_envelope_cannot_produce_a_match" file="tools/test_mtproto_forensics.py" line="434" time="0.000" /><testcase classname="tools.test_mtproto_forensics" name="test_unknown_obfuscated_transport_fails_closed" file="tools/test_mtproto_forensics.py" line="442" time="0.000" /><testcase classname="tools.test_mtproto_forensics" name="test_encrypted_frames_rejects_truncated_envelopes" file="tools/test_mtproto_forensics.py" line="447" time="0.000" /><testcase classname="tools.test_mtproto_forensics" name="test_encrypted_frames_skips_only_complete_handshake_envelopes" file="tools/test_mtproto_forensics.py" line="456" time="0.000" /><testcase classname="tools.test_mtproto_forensics" name="test_aggregate_views_cannot_establish_prior_viewing[10-10]" file="tools/test_mtproto_forensics.py" line="464" time="0.000" /><testcase classname="tools.test_mtproto_forensics" name="test_aggregate_views_cannot_establish_prior_viewing[10-11]" file="tools/test_mtproto_forensics.py" line="464" time="0.000" /><testcase classname="tools.test_mtproto_forensics" name="test_aggregate_views_cannot_establish_prior_viewing[11-10]" file="tools/test_mtproto_forensics.py" line="464" time="0.000" /><testcase classname="tools.test_mtproto_forensics" name="test_aggregate_views_cannot_establish_prior_viewing[None-5]" file="tools/test_mtproto_forensics.py" line="464" time="0.000" /><testcase classname="tools.test_mtproto_forensics" name="test_view_observation_never_requests_a_counter_increment" file="tools/test_mtproto_forensics.py" line="472" time="0.000" /><testcase classname="tools.test_mtproto_forensics" name="test_bundle_retains_exact_frames_order_and_replayable_report_without_key" file="tools/test_mtproto_forensics.py" line="484" time="0.035" /><testcase classname="tools.test_mtproto_forensics" name="test_bundle_includes_key_only_when_explicitly_requested" file="tools/test_mtproto_forensics.py" line="505" time="0.033" /><testcase classname="tools.test_mtproto_forensics" name="test_key_bundle_refuses_unverifiable_private_permissions" file="tools/test_mtproto_forensics.py" line="516" time="0.026" /><testcase classname="tools.test_mtproto_forensics" name="test_bundle_does_not_overwrite_existing_sensitive_files" file="tools/test_mtproto_forensics.py" line="526" time="0.001" /><testcase classname="tools.test_mtproto_forensics" name="test_bundle_treats_raw_pcap_only_as_an_unverified_attachment" file="tools/test_mtproto_forensics.py" line="536" time="0.038" /><testcase classname="tools.test_mtproto_forensics" name="test_invalid_bundle_frames_leave_no_partial_output" file="tools/test_mtproto_forensics.py" line="550" time="0.025" /><testcase classname="tools.test_narrative" name="test_model_every_fact_has_exact_references_and_no_invented_identity" file="tools/test_narrative.py" line="45" time="0.303" /><testcase classname="tools.test_narrative" name="test_plural_categories[ru-21-one]" file="tools/test_narrative.py" line="58" time="0.001" /><testcase classname="tools.test_narrative" name="test_plural_categories[ru-22-few]" file="tools/test_narrative.py" line="58" time="0.001" /><testcase classname="tools.test_narrative" name="test_plural_categories[uk-11-many]" file="tools/test_narrative.py" line="58" time="0.001" /><testcase classname="tools.test_narrative" name="test_plural_categories[pl-22-few]" file="tools/test_narrative.py" line="58" time="0.001" /><testcase classname="tools.test_narrative" name="test_plural_categories[pl-21-many]" file="tools/test_narrative.py" line="58" time="0.001" /><testcase classname="tools.test_narrative" name="test_plural_categories[cs-1.5-many]" file="tools/test_narrative.py" line="58" time="0.000" /><testcase classname="tools.test_narrative" name="test_plural_categories[cs-4-few]" file="tools/test_narrative.py" line="58" time="0.000" /><testcase classname="tools.test_narrative" name="test_plural_categories[sk-5-other]" file="tools/test_narrative.py" line="58" time="0.000" /><testcase classname="tools.test_narrative" name="test_plural_categories[lt-11-other]" file="tools/test_narrative.py" line="58" time="0.000" /><testcase classname="tools.test_narrative" name="test_plural_categories[lt-21-one]" file="tools/test_narrative.py" line="58" time="0.000" /><testcase classname="tools.test_narrative" name="test_plural_categories[lt-1.5-many]" file="tools/test_narrative.py" line="58" time="0.000" /><testcase classname="tools.test_narrative" name="test_plural_categories[ja-1-other]" file="tools/test_narrative.py" line="58" time="0.000" /><testcase classname="tools.test_narrative" name="test_icu_nested_parameters_and_no_payload_template_execution" file="tools/test_narrative.py" line="65" time="0.000" /><testcase classname="tools.test_narrative" name="test_pdf_html_and_svg_outputs[en]" file="tools/test_narrative.py" line="72" time="0.702"><failure message="KeyError: 'translation_review'">tmp_path = PosixPath('/tmp/pytest-of-root/pytest-6/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
&gt;       assert 'machine-assisted, not reviewed' == model['translation_review']
                                                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^
E       KeyError: 'translation_review'

tools/test_narrative.py:83: KeyError</failure></testcase><testcase classname="tools.test_narrative" name="test_pdf_html_and_svg_outputs[de]" file="tools/test_narrative.py" line="72" time="1.617"><failure message="KeyError: 'translation_review'">tmp_path = PosixPath('/tmp/pytest-of-root/pytest-6/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
&gt;       assert 'machine-assisted, not reviewed' == model['translation_review']
                                                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^
E       KeyError: 'translation_review'

tools/test_narrative.py:83: KeyError</failure></testcase><testcase classname="tools.test_narrative" name="test_pdf_html_and_svg_outputs[fr]" file="tools/test_narrative.py" line="72" time="0.714"><failure message="KeyError: 'translation_review'">tmp_path = PosixPath('/tmp/pytest-of-root/pytest-6/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
&gt;       assert 'machine-assisted, not reviewed' == model['translation_review']
                                                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^
E       KeyError: 'translation_review'

tools/test_narrative.py:83: KeyError</failure></testcase><testcase classname="tools.test_narrative" name="test_pdf_html_and_svg_outputs[es]" file="tools/test_narrative.py" line="72" time="0.719"><failure message="KeyError: 'translation_review'">tmp_path = PosixPath('/tmp/pytest-of-root/pytest-6/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
&gt;       assert 'machine-assisted, not reviewed' == model['translation_review']
                                                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^
E       KeyError: 'translation_review'

tools/test_narrative.py:83: KeyError</failure></testcase><testcase classname="tools.test_narrative" name="test_pdf_html_and_svg_outputs[it]" file="tools/test_narrative.py" line="72" time="0.705"><failure message="KeyError: 'translation_review'">tmp_path = PosixPath('/tmp/pytest-of-root/pytest-6/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
&gt;       assert 'machine-assisted, not reviewed' == model['translation_review']
                                                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^
E       KeyError: 'translation_review'

tools/test_narrative.py:83: KeyError</failure></testcase><testcase classname="tools.test_narrative" name="test_pdf_html_and_svg_outputs[pt]" file="tools/test_narrative.py" line="72" time="0.683"><failure message="KeyError: 'translation_review'">tmp_path = PosixPath('/tmp/pytest-of-root/pytest-6/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
&gt;       assert 'machine-assisted, not reviewed' == model['translation_review']
                                                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^
E       KeyError: 'translation_review'

tools/test_narrative.py:83: KeyError</failure></testcase><testcase classname="tools.test_narrative" name="test_pdf_html_and_svg_outputs[nl]" file="tools/test_narrative.py" line="72" time="1.635"><failure message="KeyError: 'translation_review'">tmp_path = PosixPath('/tmp/pytest-of-root/pytest-6/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
&gt;       assert 'machine-assisted, not reviewed' == model['translation_review']
                                                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^
E       KeyError: 'translation_review'

tools/test_narrative.py:83: KeyError</failure></testcase><testcase classname="tools.test_narrative" name="test_pdf_html_and_svg_outputs[pl]" file="tools/test_narrative.py" line="72" time="0.684"><failure message="KeyError: 'translation_review'">tmp_path = PosixPath('/tmp/pytest-of-root/pytest-6/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
&gt;       assert 'machine-assisted, not reviewed' == model['translation_review']
                                                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^
E       KeyError: 'translation_review'

tools/test_narrative.py:83: KeyError</failure></testcase><testcase classname="tools.test_narrative" name="test_pdf_html_and_svg_outputs[cs]" file="tools/test_narrative.py" line="72" time="0.673"><failure message="KeyError: 'translation_review'">tmp_path = PosixPath('/tmp/pytest-of-root/pytest-6/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
&gt;       assert 'machine-assisted, not reviewed' == model['translation_review']
                                                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^
E       KeyError: 'translation_review'

tools/test_narrative.py:83: KeyError</failure></testcase><testcase classname="tools.test_narrative" name="test_pdf_html_and_svg_outputs[sk]" file="tools/test_narrative.py" line="72" time="0.649"><failure message="KeyError: 'translation_review'">tmp_path = PosixPath('/tmp/pytest-of-root/pytest-6/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
&gt;       assert 'machine-assisted, not reviewed' == model['translation_review']
                                                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^
E       KeyError: 'translation_review'

tools/test_narrative.py:83: KeyError</failure></testcase><testcase classname="tools.test_narrative" name="test_pdf_html_and_svg_outputs[uk]" file="tools/test_narrative.py" line="72" time="0.674"><failure message="KeyError: 'translation_review'">tmp_path = PosixPath('/tmp/pytest-of-root/pytest-6/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
&gt;       assert 'machine-assisted, not reviewed' == model['translation_review']
                                                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^
E       KeyError: 'translation_review'

tools/test_narrative.py:83: KeyError</failure></testcase><testcase classname="tools.test_narrative" name="test_pdf_html_and_svg_outputs[ro]" file="tools/test_narrative.py" line="72" time="0.765"><failure message="KeyError: 'translation_review'">tmp_path = PosixPath('/tmp/pytest-of-root/pytest-6/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
&gt;       assert 'machine-assisted, not reviewed' == model['translation_review']
                                                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^
E       KeyError: 'translation_review'

tools/test_narrative.py:83: KeyError</failure></testcase><testcase classname="tools.test_narrative" name="test_pdf_html_and_svg_outputs[bg]" file="tools/test_narrative.py" line="72" time="1.569"><failure message="KeyError: 'translation_review'">tmp_path = PosixPath('/tmp/pytest-of-root/pytest-6/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
&gt;       assert 'machine-assisted, not reviewed' == model['translation_review']
                                                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^
E       KeyError: 'translation_review'

tools/test_narrative.py:83: KeyError</failure></testcase><testcase classname="tools.test_narrative" name="test_pdf_html_and_svg_outputs[hu]" file="tools/test_narrative.py" line="72" time="0.673"><failure message="KeyError: 'translation_review'">tmp_path = PosixPath('/tmp/pytest-of-root/pytest-6/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
&gt;       assert 'machine-assisted, not reviewed' == model['translation_review']
                                                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^
E       KeyError: 'translation_review'

tools/test_narrative.py:83: KeyError</failure></testcase><testcase classname="tools.test_narrative" name="test_pdf_html_and_svg_outputs[el]" file="tools/test_narrative.py" line="72" time="0.746"><failure message="KeyError: 'translation_review'">tmp_path = PosixPath('/tmp/pytest-of-root/pytest-6/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
&gt;       assert 'machine-assisted, not reviewed' == model['translation_review']
                                                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^
E       KeyError: 'translation_review'

tools/test_narrative.py:83: KeyError</failure></testcase><testcase classname="tools.test_narrative" name="test_pdf_html_and_svg_outputs[sv]" file="tools/test_narrative.py" line="72" time="0.942"><failure message="KeyError: 'translation_review'">tmp_path = PosixPath('/tmp/pytest-of-root/pytest-6/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
&gt;       assert 'machine-assisted, not reviewed' == model['translation_review']
                                                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^
E       KeyError: 'translation_review'

tools/test_narrative.py:83: KeyError</failure></testcase><testcase classname="tools.test_narrative" name="test_pdf_html_and_svg_outputs[da]" file="tools/test_narrative.py" line="72" time="0.866"><failure message="KeyError: 'translation_review'">tmp_path = PosixPath('/tmp/pytest-of-root/pytest-6/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
&gt;       assert 'machine-assisted, not reviewed' == model['translation_review']
                                                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^
E       KeyError: 'translation_review'

tools/test_narrative.py:83: KeyError</failure></testcase><testcase classname="tools.test_narrative" name="test_pdf_html_and_svg_outputs[fi]" file="tools/test_narrative.py" line="72" time="0.787"><failure message="KeyError: 'translation_review'">tmp_path = PosixPath('/tmp/pytest-of-root/pytest-6/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
&gt;       assert 'machine-assisted, not reviewed' == model['translation_review']
                                                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^
E       KeyError: 'translation_review'

tools/test_narrative.py:83: KeyError</failure></testcase><testcase classname="tools.test_narrative" name="test_pdf_html_and_svg_outputs[no]" file="tools/test_narrative.py" line="72" time="1.625"><failure message="KeyError: 'translation_review'">tmp_path = PosixPath('/tmp/pytest-of-root/pytest-6/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
&gt;       assert 'machine-assisted, not reviewed' == model['translation_review']
                                                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^
E       KeyError: 'translation_review'

tools/test_narrative.py:83: KeyError</failure></testcase><testcase classname="tools.test_narrative" name="test_pdf_html_and_svg_outputs[lt]" file="tools/test_narrative.py" line="72" time="0.761"><failure message="KeyError: 'translation_review'">tmp_path = PosixPath('/tmp/pytest-of-root/pytest-6/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
&gt;       assert 'machine-assisted, not reviewed' == model['translation_review']
                                                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^
E       KeyError: 'translation_review'

tools/test_narrative.py:83: KeyError</failure></testcase><testcase classname="tools.test_narrative" name="test_pdf_html_and_svg_outputs[lv]" file="tools/test_narrative.py" line="72" time="0.736"><failure message="KeyError: 'translation_review'">tmp_path = PosixPath('/tmp/pytest-of-root/pytest-6/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
&gt;       assert 'machine-assisted, not reviewed' == model['translation_review']
                                                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^
E       KeyError: 'translation_review'

tools/test_narrative.py:83: KeyError</failure></testcase><testcase classname="tools.test_narrative" name="test_pdf_html_and_svg_outputs[et]" file="tools/test_narrative.py" line="72" time="0.749"><failure message="KeyError: 'translation_review'">tmp_path = PosixPath('/tmp/pytest-of-root/pytest-6/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
&gt;       assert 'machine-assisted, not reviewed' == model['translation_review']
                                                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^
E       KeyError: 'translation_review'

tools/test_narrative.py:83: KeyError</failure></testcase><testcase classname="tools.test_narrative" name="test_pdf_html_and_svg_outputs[tr]" file="tools/test_narrative.py" line="72" time="0.710"><failure message="KeyError: 'translation_review'">tmp_path = PosixPath('/tmp/pytest-of-root/pytest-6/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
&gt;       assert 'machine-assisted, not reviewed' == model['translation_review']
                                                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^
E       KeyError: 'translation_review'

tools/test_narrative.py:83: KeyError</failure></testcase><testcase classname="tools.test_narrative" name="test_pdf_html_and_svg_outputs[ja]" file="tools/test_narrative.py" line="72" time="1.643"><failure message="KeyError: 'translation_review'">tmp_path = PosixPath('/tmp/pytest-of-root/pytest-6/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
&gt;       assert 'machine-assisted, not reviewed' == model['translation_review']
                                                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^
E       KeyError: 'translation_review'

tools/test_narrative.py:83: KeyError</failure></testcase><testcase classname="tools.test_narrative" name="test_pdf_html_and_svg_outputs[zh]" file="tools/test_narrative.py" line="72" time="0.706"><failure message="KeyError: 'translation_review'">tmp_path = PosixPath('/tmp/pytest-of-root/pytest-6/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
&gt;       assert 'machine-assisted, not reviewed' == model['translation_review']
                                                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^
E       KeyError: 'translation_review'

tools/test_narrative.py:83: KeyError</failure></testcase><testcase classname="tools.test_narrative" name="test_pdf_html_and_svg_outputs[zh-Hant]" file="tools/test_narrative.py" line="72" time="0.765"><failure message="KeyError: 'translation_review'">tmp_path = PosixPath('/tmp/pytest-of-root/pytest-6/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
&gt;       assert 'machine-assisted, not reviewed' == model['translation_review']
                                                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^
E       KeyError: 'translation_review'

tools/test_narrative.py:83: KeyError</failure></testcase><testcase classname="tools.test_narrative" name="test_pdf_html_and_svg_outputs[ko]" file="tools/test_narrative.py" line="72" time="0.769"><failure message="KeyError: 'translation_review'">tmp_path = PosixPath('/tmp/pytest-of-root/pytest-6/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
&gt;       assert 'machine-assisted, not reviewed' == model['translation_review']
                                                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^
E       KeyError: 'translation_review'

tools/test_narrative.py:83: KeyError</failure></testcase><testcase classname="tools.test_narrative" name="test_pdf_html_and_svg_outputs[ar]" file="tools/test_narrative.py" line="72" time="1.021"><failure message="KeyError: 'translation_review'">tmp_path = PosixPath('/tmp/pytest-of-root/pytest-6/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
&gt;       assert 'machine-assisted, not reviewed' == model['translation_review']
                                                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^
E       KeyError: 'translation_review'

tools/test_narrative.py:83: KeyError</failure></testcase><testcase classname="tools.test_narrative" name="test_pdf_html_and_svg_outputs[he]" file="tools/test_narrative.py" line="72" time="1.080"><failure message="KeyError: 'translation_review'">tmp_path = PosixPath('/tmp/pytest-of-root/pytest-6/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
&gt;       assert 'machine-assisted, not reviewed' == model['translation_review']
                                                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^
E       KeyError: 'translation_review'

tools/test_narrative.py:83: KeyError</failure></testcase><testcase classname="tools.test_narrative" name="test_pdf_html_and_svg_outputs[fa]" file="tools/test_narrative.py" line="72" time="2.036"><failure message="KeyError: 'translation_review'">tmp_path = PosixPath('/tmp/pytest-of-root/pytest-6/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
&gt;       assert 'machine-assisted, not reviewed' == model['translation_review']
                                                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^
E       KeyError: 'translation_review'

tools/test_narrative.py:83: KeyError</failure></testcase><testcase classname="tools.test_narrative" name="test_pdf_html_and_svg_outputs[hi]" file="tools/test_narrative.py" line="72" time="1.020"><failure message="KeyError: 'translation_review'">tmp_path = PosixPath('/tmp/pytest-of-root/pytest-6/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
&gt;       assert 'machine-assisted, not reviewed' == model['translation_review']
                                                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^
E       KeyError: 'translation_review'

tools/test_narrative.py:83: KeyError</failure></testcase><testcase classname="tools.test_narrative" name="test_pdf_html_and_svg_outputs[ur]" file="tools/test_narrative.py" line="72" time="1.050"><failure message="KeyError: 'translation_review'">tmp_path = PosixPath('/tmp/pytest-of-root/pytest-6/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
&gt;       assert 'machine-assisted, not reviewed' == model['translation_review']
                                                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^
E       KeyError: 'translation_review'

tools/test_narrative.py:83: KeyError</failure></testcase><testcase classname="tools.test_narrative" name="test_pdf_html_and_svg_outputs[bn]" file="tools/test_narrative.py" line="72" time="1.007"><failure message="KeyError: 'translation_review'">tmp_path = PosixPath('/tmp/pytest-of-root/pytest-6/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
&gt;       assert 'machine-assisted, not reviewed' == model['translation_review']
                                                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^
E       KeyError: 'translation_review'

tools/test_narrative.py:83: KeyError</failure></testcase><testcase classname="tools.test_narrative" name="test_pdf_html_and_svg_outputs[id]" file="tools/test_narrative.py" line="72" time="0.713"><failure message="KeyError: 'translation_review'">tmp_path = PosixPath('/tmp/pytest-of-root/pytest-6/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
&gt;       assert 'machine-assisted, not reviewed' == model['translation_review']
                                                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^
E       KeyError: 'translation_review'

tools/test_narrative.py:83: KeyError</failure></testcase><testcase classname="tools.test_narrative" name="test_pdf_html_and_svg_outputs[ms]" file="tools/test_narrative.py" line="72" time="1.569"><failure message="KeyError: 'translation_review'">tmp_path = PosixPath('/tmp/pytest-of-root/pytest-6/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
&gt;       assert 'machine-assisted, not reviewed' == model['translation_review']
                                                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^
E       KeyError: 'translation_review'

tools/test_narrative.py:83: KeyError</failure></testcase><testcase classname="tools.test_narrative" name="test_pdf_html_and_svg_outputs[vi]" file="tools/test_narrative.py" line="72" time="0.746"><failure message="KeyError: 'translation_review'">tmp_path = PosixPath('/tmp/pytest-of-root/pytest-6/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
&gt;       assert 'machine-assisted, not reviewed' == model['translation_review']
                                                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^
E       KeyError: 'translation_review'

tools/test_narrative.py:83: KeyError</failure></testcase><testcase classname="tools.test_narrative" name="test_pdf_html_and_svg_outputs[th]" file="tools/test_narrative.py" line="72" time="0.846"><failure message="KeyError: 'translation_review'">tmp_path = PosixPath('/tmp/pytest-of-root/pytest-6/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
&gt;       assert 'machine-assisted, not reviewed' == model['translation_review']
                                                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^
E       KeyError: 'translation_review'

tools/test_narrative.py:83: KeyError</failure></testcase><testcase classname="tools.test_narrative" name="test_pdf_html_and_svg_outputs[uz]" file="tools/test_narrative.py" line="72" time="0.675"><failure message="KeyError: 'translation_review'">tmp_path = PosixPath('/tmp/pytest-of-root/pytest-6/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
&gt;       assert 'machine-assisted, not reviewed' == model['translation_review']
                                                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^
E       KeyError: 'translation_review'

tools/test_narrative.py:83: KeyError</failure></testcase><testcase classname="tools.test_narrative" name="test_pdf_html_and_svg_outputs[ru]" file="tools/test_narrative.py" line="72" time="0.721"><failure message="KeyError: 'translation_review'">tmp_path = PosixPath('/tmp/pytest-of-root/pytest-6/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
&gt;       assert 'machine-assisted, not reviewed' == model['translation_review']
                                                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^
E       KeyError: 'translation_review'

tools/test_narrative.py:83: KeyError</failure></testcase><testcase classname="tools.test_narrative" name="test_jurisdictions_change_only_the_terms_section" file="tools/test_narrative.py" line="95" time="0.490"><failure message="assert 3 == 1&#10; +  where 3 = len({'&lt;!doctype html&gt;&lt;html lang=&quot;de&quot; dir=&quot;ltr&quot;&gt;&lt;head&gt;&lt;meta charset=&quot;utf-8&quot;&gt;&lt;meta name=&quot;viewport&quot; content=&quot;width=device-wid...c8f7a0d69ff5a7e83a7095b9b2112ec&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/section&gt;&lt;footer&gt;Beweisbericht&lt;/footer&gt;&lt;/main&gt;&lt;/body&gt;&lt;/html&gt;'})&#10;[+1 more line; full report in element text]">tmp_path = PosixPath('/tmp/pytest-of-root/pytest-6/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'&lt;section id="jurisdiction"&gt;.*?&lt;/section&gt;', '', h) for h in rendered]
&gt;       assert len(set(stripped)) == 1
E       assert 3 == 1
E        +  where 3 = len({'&lt;!doctype html&gt;&lt;html lang="de" dir="ltr"&gt;&lt;head&gt;&lt;meta charset="utf-8"&gt;&lt;meta name="viewport" content="width=device-wid...c8f7a0d69ff5a7e83a7095b9b2112ec&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/section&gt;&lt;footer&gt;Beweisbericht&lt;/footer&gt;&lt;/main&gt;&lt;/body&gt;&lt;/html&gt;'})
E        +    where {'&lt;!doctype html&gt;&lt;html lang="de" dir="ltr"&gt;&lt;head&gt;&lt;meta charset="utf-8"&gt;&lt;meta name="viewport" content="width=device-wid...c8f7a0d69ff5a7e83a7095b9b2112ec&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/section&gt;&lt;footer&gt;Beweisbericht&lt;/footer&gt;&lt;/main&gt;&lt;/body&gt;&lt;/html&gt;'} = set(['&lt;!doctype html&gt;&lt;html lang="de" dir="ltr"&gt;&lt;head&gt;&lt;meta charset="utf-8"&gt;&lt;meta name="viewport" content="width=device-wid...c8f7a0d69ff5a7e83a7095b9b2112ec&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/section&gt;&lt;footer&gt;Beweisbericht&lt;/footer&gt;&lt;/main&gt;&lt;/body&gt;&lt;/html&gt;'])

tools/test_narrative.py:105: AssertionError</failure></testcase><testcase classname="tools.test_narrative" name="test_claims_do_not_become_checks_and_untrusted_markup_is_escaped" file="tools/test_narrative.py" line="108" time="0.356" /><testcase classname="tools.test_narrative" name="test_original_signed_legacy_fixture" file="tools/test_narrative.py" line="125" time="0.350" /><testcase classname="tools.test_narrative" name="test_catalog_policy_and_plural_edge_cases" file="tools/test_narrative.py" line="131" time="0.002"><failure message="FileNotFoundError: [Errno 2] No such file or directory: '/workspace/qa/src/db86ca0b4e82515795ccc1c5e32a55579582c0fe/tgwitness/narrative/review-policy.json'">def test_catalog_policy_and_plural_edge_cases():
        from check_narrative_texts import check
&gt;       assert check() == []
               ^^^^^^^

tools/test_narrative.py:134: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
tools/check_narrative_texts.py:14: in check
    policy = json.loads((ROOT / 'review-policy.json').read_text(encoding='utf-8'))
                        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
/usr/lib/python3.12/pathlib.py:1029: in read_text
    with self.open(mode='r', encoding=encoding, errors=errors) as f:
         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = PosixPath('/workspace/qa/src/db86ca0b4e82515795ccc1c5e32a55579582c0fe/tgwitness/narrative/review-policy.json')
mode = 'r', buffering = -1, encoding = 'utf-8', errors = None, newline = None

    def open(self, mode='r', buffering=-1, encoding=None,
             errors=None, newline=None):
        """
        Open the file pointed by this path and return a file object, as
        the built-in open() function does.
        """
        if "b" not in mode:
            encoding = io.text_encoding(encoding)
&gt;       return io.open(self, mode, buffering, encoding, errors, newline)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
E       FileNotFoundError: [Errno 2] No such file or directory: '/workspace/qa/src/db86ca0b4e82515795ccc1c5e32a55579582c0fe/tgwitness/narrative/review-policy.json'

/usr/lib/python3.12/pathlib.py:1015: FileNotFoundError</failure></testcase><testcase classname="tools.test_narrative" name="test_golden_model_is_language_independent" file="tools/test_narrative.py" line="143" time="0.001"><failure message="AssertionError: assert {'format': 't...e': None, ...} == {'format': 't...e': None, ...}&#10;  &#10;  Omitting 6 identical items, use -vv to show&#10;  Differing items:&#10;  {'limits': [{'template_key': 'limit.truth', 'params': {}}]} != {'limits': [{'template_key': 'limit.truth', 'params': {}}, {'template_key': 'limit.review', 'params': {}}]}&#10;  Right contains 1 more item:&#10;  {'translation_review': 'machine-assisted, not reviewed'}&#10;  Use -v to get more diff">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'))
&gt;       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</failure></testcase><testcase classname="tools.test_narrative" name="test_restart_links_signed_endpoints_without_inventing_a_cause" file="tools/test_narrative.py" line="160" time="0.000" /><testcase classname="tools.test_narrative" name="test_restart_preserves_the_full_recorded_time_range_after_clock_changes" file="tools/test_narrative.py" line="170" time="0.000" /><testcase classname="tools.test_narrative" name="test_modified_archive_cannot_produce_a_report" file="tools/test_narrative.py" line="185" time="0.339" /><testcase classname="tools.test_narrative" name="test_anchor_attaches_only_to_covered_facts_and_preserves_numeric_values" file="tools/test_narrative.py" line="200" time="0.003" /><testcase classname="tools.test_narrative_config" name="test_profile_precedence_relative_paths_and_explicit_false" file="tools/test_narrative_config.py" line="31" time="0.005" /><testcase classname="tools.test_narrative_config" name="test_invalid_or_verdict_overriding_settings_are_rejected[settings0]" file="tools/test_narrative_config.py" line="45" time="0.001" /><testcase classname="tools.test_narrative_config" name="test_invalid_or_verdict_overriding_settings_are_rejected[settings1]" file="tools/test_narrative_config.py" line="45" time="0.001" /><testcase classname="tools.test_narrative_config" name="test_invalid_or_verdict_overriding_settings_are_rejected[settings2]" file="tools/test_narrative_config.py" line="45" time="0.001" /><testcase classname="tools.test_narrative_config" name="test_invalid_or_verdict_overriding_settings_are_rejected[settings3]" file="tools/test_narrative_config.py" line="45" time="0.001" /><testcase classname="tools.test_narrative_config" name="test_invalid_or_verdict_overriding_settings_are_rejected[settings4]" file="tools/test_narrative_config.py" line="45" time="0.001" /><testcase classname="tools.test_narrative_config" name="test_invalid_or_verdict_overriding_settings_are_rejected[settings5]" file="tools/test_narrative_config.py" line="45" time="0.001" /><testcase classname="tools.test_narrative_config" name="test_invalid_or_verdict_overriding_settings_are_rejected[settings6]" file="tools/test_narrative_config.py" line="45" time="0.001" /><testcase classname="tools.test_narrative_config" name="test_invalid_or_verdict_overriding_settings_are_rejected[settings7]" file="tools/test_narrative_config.py" line="45" time="0.001" /><testcase classname="tools.test_narrative_config" name="test_invalid_or_verdict_overriding_settings_are_rejected[settings8]" file="tools/test_narrative_config.py" line="45" time="0.001" /><testcase classname="tools.test_narrative_config" name="test_invalid_or_verdict_overriding_settings_are_rejected[settings9]" file="tools/test_narrative_config.py" line="45" time="0.001" /><testcase classname="tools.test_narrative_config" name="test_invalid_or_verdict_overriding_settings_are_rejected[settings10]" file="tools/test_narrative_config.py" line="45" time="0.001" /><testcase classname="tools.test_narrative_config" name="test_invalid_or_verdict_overriding_settings_are_rejected[settings11]" file="tools/test_narrative_config.py" line="45" time="0.001" /><testcase classname="tools.test_narrative_config" name="test_invalid_or_verdict_overriding_settings_are_rejected[settings12]" file="tools/test_narrative_config.py" line="45" time="0.001" /><testcase classname="tools.test_narrative_config" name="test_invalid_or_verdict_overriding_settings_are_rejected[settings13]" file="tools/test_narrative_config.py" line="45" time="0.001" /><testcase classname="tools.test_narrative_config" name="test_invalid_or_verdict_overriding_settings_are_rejected[settings14]" file="tools/test_narrative_config.py" line="45" time="0.001" /><testcase classname="tools.test_narrative_config" name="test_invalid_or_verdict_overriding_settings_are_rejected[settings15]" file="tools/test_narrative_config.py" line="45" time="0.001" /><testcase classname="tools.test_narrative_config" name="test_invalid_or_verdict_overriding_settings_are_rejected[settings16]" file="tools/test_narrative_config.py" line="45" time="0.001" /><testcase classname="tools.test_narrative_config" name="test_duplicates_oversized_and_invalid_unused_profiles_fail" file="tools/test_narrative_config.py" line="58" time="0.001" /><testcase classname="tools.test_narrative_config" name="test_missing_profiles_and_unknown_document_fields_fail" file="tools/test_narrative_config.py" line="71" time="0.001" /><testcase classname="tools.test_narrative_config" name="test_json_only_skips_fonts_and_diagrams_and_records_public_settings" file="tools/test_narrative_config.py" line="84" time="0.297" /><testcase classname="tools.test_narrative_config" name="test_optional_diagrams_cannot_hide_assurance_limits_or_references[selected0]" file="tools/test_narrative_config.py" line="101" time="0.338"><failure message="KeyError: 'limit.review'">tmp_path = PosixPath('/tmp/pytest-of-root/pytest-6/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('&lt;svg ') == len(selected)
        assert not (out / 'diagrams').exists()
        text = Texts('en')
&gt;       assert text('heading.limits') in html and text('limit.review') in html
                                                  ^^^^^^^^^^^^^^^^^^^^

tools/test_narrative_config.py:111: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = &lt;tgwitness.narrative.text.Texts object at 0x747f5c333680&gt;
key = 'limit.review', params = {}

    def __call__(self, key, **params):
&gt;       nodes = parse(self.values[key])
                      ^^^^^^^^^^^^^^^^
E       KeyError: 'limit.review'

tgwitness/narrative/text.py:138: KeyError</failure></testcase><testcase classname="tools.test_narrative_config" name="test_optional_diagrams_cannot_hide_assurance_limits_or_references[selected1]" file="tools/test_narrative_config.py" line="101" time="0.456"><failure message="KeyError: 'limit.review'">tmp_path = PosixPath('/tmp/pytest-of-root/pytest-6/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('&lt;svg ') == len(selected)
        assert not (out / 'diagrams').exists()
        text = Texts('en')
&gt;       assert text('heading.limits') in html and text('limit.review') in html
                                                  ^^^^^^^^^^^^^^^^^^^^

tools/test_narrative_config.py:111: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = &lt;tgwitness.narrative.text.Texts object at 0x747f42f99880&gt;
key = 'limit.review', params = {}

    def __call__(self, key, **params):
&gt;       nodes = parse(self.values[key])
                      ^^^^^^^^^^^^^^^^
E       KeyError: 'limit.review'

tgwitness/narrative/text.py:138: KeyError</failure></testcase><testcase classname="tools.test_narrative_config" name="test_optional_diagrams_cannot_hide_assurance_limits_or_references[selected2]" file="tools/test_narrative_config.py" line="101" time="0.298"><failure message="assert 1 == 2&#10; +  where 1 = &lt;built-in method count of str object at 0x2caadbb0&gt;('&lt;svg ')&#10; +    where &lt;built-in method count of str object at 0x2caadbb0&gt; = '&lt;!doctype html&gt;&lt;html lang=&quot;en&quot; dir=&quot;ltr&quot;&gt;&lt;head&gt;&lt;meta charset=&quot;utf-8&quot;&gt;&lt;meta name=&quot;viewport&quot; content=&quot;width=device-widt...a0d69ff5a7e83a7095b9b2112ec&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/section&gt;&lt;footer&gt;Evidence narrative&lt;/footer&gt;&lt;/main&gt;&lt;/body&gt;&lt;/html&gt;'.count&#10; +  and   2 = len(['ladder', 'files'])">tmp_path = PosixPath('/tmp/pytest-of-root/pytest-6/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')
&gt;       assert html.count('&lt;svg ') == len(selected)
E       assert 1 == 2
E        +  where 1 = &lt;built-in method count of str object at 0x2caadbb0&gt;('&lt;svg ')
E        +    where &lt;built-in method count of str object at 0x2caadbb0&gt; = '&lt;!doctype html&gt;&lt;html lang="en" dir="ltr"&gt;&lt;head&gt;&lt;meta charset="utf-8"&gt;&lt;meta name="viewport" content="width=device-widt...a0d69ff5a7e83a7095b9b2112ec&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/section&gt;&lt;footer&gt;Evidence narrative&lt;/footer&gt;&lt;/main&gt;&lt;/body&gt;&lt;/html&gt;'.count
E        +  and   2 = len(['ladder', 'files'])

tools/test_narrative_config.py:108: AssertionError</failure></testcase><testcase classname="tools.test_narrative_config" name="test_svg_selection_and_scene_size_preserve_all_evidence" file="tools/test_narrative_config.py" line="116" time="0.282" /><testcase classname="tools.test_narrative_config" name="test_limits_fail_without_silent_truncation_or_partial_report" file="tools/test_narrative_config.py" line="130" time="0.249" /><testcase classname="tools.test_narrative_config" name="test_minimum_tier_pin_and_wrong_pin_are_distinct_failures" file="tools/test_narrative_config.py" line="140" time="0.297" /><testcase classname="tools.test_narrative_config" name="test_witness_fingerprint_without_matching_witness_cannot_satisfy_pin" file="tools/test_narrative_config.py" line="159" time="0.276" /><testcase classname="tools.test_narrative_config" name="test_required_witness_anchored_profile_checks_actual_signed_archives[confirmed]" file="tools/test_narrative_config.py" line="166" time="0.591" /><testcase classname="tools.test_narrative_config" name="test_required_witness_anchored_profile_checks_actual_signed_archives[missing]" file="tools/test_narrative_config.py" line="166" time="0.563" /><testcase classname="tools.test_narrative_config" name="test_required_witness_anchored_profile_checks_actual_signed_archives[mismatch]" file="tools/test_narrative_config.py" line="166" time="0.647" /><testcase classname="tools.test_narrative_config" name="test_profile_routes_network_flags_to_verifier_without_enabling_them_implicitly" file="tools/test_narrative_config.py" line="222" time="0.357" /><testcase classname="tools.test_narrative_config" name="test_configuration_cannot_bypass_archive_authentication" file="tools/test_narrative_config.py" line="234" time="0.313" /><testcase classname="tools.test_narrative_config" name="test_example_is_usable_and_never_overwrites_existing_trust_profile" file="tools/test_narrative_config.py" line="250" time="0.005" /><testcase classname="tools.test_narrative_config" name="test_real_cli_profile_overrides_and_exit_codes" file="tools/test_narrative_config.py" line="267" time="1.731" /><testcase classname="tools.test_narrative_config" name="test_real_cli_write_config_and_invalid_configuration_errors" file="tools/test_narrative_config.py" line="288" time="1.401" /><testcase classname="tools.test_opsec" name="test_self_check_reports_risks_and_what_a_bot_sees" file="tools/test_opsec.py" line="58" time="0.217" /><testcase classname="tools.test_opsec" name="test_presence_is_hidden_only_when_chosen_and_failures_are_recorded" file="tools/test_opsec.py" line="79" time="0.260" /><testcase classname="tools.test_opsec" name="test_link_risks[https://t.me/proxy?server=192.0.2.1&amp;port=443&amp;secret=synthetic-telegram_proxy]" file="tools/test_opsec.py" line="92" time="0.000" /><testcase classname="tools.test_opsec" name="test_link_risks[tg://socks?server=192.0.2.1&amp;port=1080-telegram_proxy]" file="tools/test_opsec.py" line="92" time="0.000" /><testcase classname="tools.test_opsec" name="test_link_risks[https://t.me/fictional/s/6-telegram_story]" file="tools/test_opsec.py" line="92" time="0.000" /><testcase classname="tools.test_opsec" name="test_link_risks[g\u0456thub.com-mixed_script]" file="tools/test_opsec.py" line="92" time="0.000" /><testcase classname="tools.test_opsec" name="test_link_risks[https://\u0440\u0430y\u0440\u0430l.com/login-mixed_script]" file="tools/test_opsec.py" line="92" time="0.000" /><testcase classname="tools.test_opsec" name="test_link_risks[\u043f\u0440\u0438\u043c\u0435\u0440.\u0440\u0444-None]" file="tools/test_opsec.py" line="92" time="0.000" /><testcase classname="tools.test_opsec" name="test_link_risks[\u043f\u0440\u0438\u043c\u0435\u0440.com-None]" file="tools/test_opsec.py" line="92" time="0.000" /><testcase classname="tools.test_opsec" name="test_link_risks[xn--e1afmkfd.xn--p1ai-None]" file="tools/test_opsec.py" line="92" time="0.001" /><testcase classname="tools.test_opsec" name="test_link_risks[https://github.com-None]" file="tools/test_opsec.py" line="92" time="0.000" /><testcase classname="tools.test_opsec" name="test_link_risks[https://t.me/fictional-None]" file="tools/test_opsec.py" line="92" time="0.000" /><testcase classname="tools.test_opsec" name="test_hidden_proxy_or_story_behind_other_text_is_deceptive" file="tools/test_opsec.py" line="101" time="0.000" /><testcase classname="tools.test_opsec" name="test_protocol_warns_about_risky_links_in_replies_and_buttons" file="tools/test_opsec.py" line="109" time="0.001" /><testcase classname="tools.test_parallel_exports" name="test_two_exports_on_different_accounts_run_at_the_same_time" file="tools/test_parallel_exports.py" line="63" time="4.480" /><testcase classname="tools.test_parallel_exports" name="test_an_account_of_a_running_export_cannot_join_another" file="tools/test_parallel_exports.py" line="102" time="1.157" /><testcase classname="tools.test_parallel_exports" name="test_start_refuses_an_export_that_does_not_fit_on_disk" file="tools/test_parallel_exports.py" line="122" time="2.321" /><testcase classname="tools.test_parallel_exports" name="test_working_files_stay_until_done_and_only_the_archive_remains" file="tools/test_parallel_exports.py" line="144" time="3.226" /><testcase classname="tools.test_password_export" name="test_password_roundtrip_exact_chunks_and_renaming[tgwitness.verifier.password]" file="tools/test_password_export.py" line="33" time="0.471" /><testcase classname="tools.test_password_export" name="test_password_roundtrip_exact_chunks_and_renaming[tgwitness.verify]" file="tools/test_password_export.py" line="33" time="0.471" /><testcase classname="tools.test_password_export" name="test_password_rejects_damage_without_plaintext[tgwitness.verifier.password-truncated]" file="tools/test_password_export.py" line="42" time="0.480" /><testcase classname="tools.test_password_export" name="test_password_rejects_damage_without_plaintext[tgwitness.verifier.password-trailing]" file="tools/test_password_export.py" line="42" time="0.476" /><testcase classname="tools.test_password_export" name="test_password_rejects_damage_without_plaintext[tgwitness.verifier.password-salt]" file="tools/test_password_export.py" line="42" time="0.485" /><testcase classname="tools.test_password_export" name="test_password_rejects_damage_without_plaintext[tgwitness.verifier.password-password]" file="tools/test_password_export.py" line="42" time="0.487" /><testcase classname="tools.test_password_export" name="test_password_rejects_damage_without_plaintext[tgwitness.verifier.password-length]" file="tools/test_password_export.py" line="42" time="0.477" /><testcase classname="tools.test_password_export" name="test_password_rejects_damage_without_plaintext[tgwitness.verifier.password-missing_last]" file="tools/test_password_export.py" line="42" time="0.473" /><testcase classname="tools.test_password_export" name="test_password_rejects_damage_without_plaintext[tgwitness.verifier.password-reordered]" file="tools/test_password_export.py" line="42" time="0.484" /><testcase classname="tools.test_password_export" name="test_password_rejects_damage_without_plaintext[tgwitness.verify-truncated]" file="tools/test_password_export.py" line="42" time="0.485" /><testcase classname="tools.test_password_export" name="test_password_rejects_damage_without_plaintext[tgwitness.verify-trailing]" file="tools/test_password_export.py" line="42" time="0.487" /><testcase classname="tools.test_password_export" name="test_password_rejects_damage_without_plaintext[tgwitness.verify-salt]" file="tools/test_password_export.py" line="42" time="0.473" /><testcase classname="tools.test_password_export" name="test_password_rejects_damage_without_plaintext[tgwitness.verify-password]" file="tools/test_password_export.py" line="42" time="0.469" /><testcase classname="tools.test_password_export" name="test_password_rejects_damage_without_plaintext[tgwitness.verify-length]" file="tools/test_password_export.py" line="42" time="0.488" /><testcase classname="tools.test_password_export" name="test_password_rejects_damage_without_plaintext[tgwitness.verify-missing_last]" file="tools/test_password_export.py" line="42" time="0.479" /><testcase classname="tools.test_password_export" name="test_password_rejects_damage_without_plaintext[tgwitness.verify-reordered]" file="tools/test_password_export.py" line="42" time="0.485" /><testcase classname="tools.test_password_export" name="test_password_partial_final_chunk[tgwitness.verifier.password-0]" file="tools/test_password_export.py" line="73" time="0.461" /><testcase classname="tools.test_password_export" name="test_password_partial_final_chunk[tgwitness.verifier.password-1]" file="tools/test_password_export.py" line="73" time="0.465" /><testcase classname="tools.test_password_export" name="test_password_partial_final_chunk[tgwitness.verifier.password-1048593]" file="tools/test_password_export.py" line="73" time="0.465" /><testcase classname="tools.test_password_export" name="test_password_partial_final_chunk[tgwitness.verify-0]" file="tools/test_password_export.py" line="73" time="0.463" /><testcase classname="tools.test_password_export" name="test_password_partial_final_chunk[tgwitness.verify-1]" file="tools/test_password_export.py" line="73" time="0.463" /><testcase classname="tools.test_password_export" name="test_password_partial_final_chunk[tgwitness.verify-1048593]" file="tools/test_password_export.py" line="73" time="0.466" /><testcase classname="tools.test_password_export" name="test_password_never_overwrites[tgwitness.verifier.password]" file="tools/test_password_export.py" line="82" time="0.703" /><testcase classname="tools.test_password_export" name="test_password_never_overwrites[tgwitness.verify]" file="tools/test_password_export.py" line="82" time="0.698" /><testcase classname="tools.test_password_export" name="test_password_standalone_command" file="tools/test_password_export.py" line="93" time="0.605" /><testcase classname="tools.test_password_export" name="test_password_export_keeps_zip_compatibility[tgwitness.verifier.password]" file="tools/test_password_export.py" line="106" time="0.499" /><testcase classname="tools.test_password_export" name="test_password_export_keeps_zip_compatibility[tgwitness.verify]" file="tools/test_password_export.py" line="106" time="0.467" /><testcase classname="tools.test_password_export" name="test_password_export_api_and_retained_download" file="tools/test_password_export.py" line="124" time="1.225" /><testcase classname="tools.test_password_export" name="test_password_handover_keeps_scope_signatures_and_retained_download[workspace-owner]" file="tools/test_password_export.py" line="151" time="2.898" /><testcase classname="tools.test_password_export" name="test_password_handover_keeps_scope_signatures_and_retained_download[scoped-owner]" file="tools/test_password_export.py" line="151" time="1.955" /><testcase classname="tools.test_password_export" name="test_password_dossier_preserves_signature_and_chat_boundary" file="tools/test_password_export.py" line="216" time="1.184" /><testcase classname="tools.test_password_export" name="test_password_export_collision_preserves_existing_output[zip]" file="tools/test_password_export.py" line="261" time="0.001" /><testcase classname="tools.test_password_export" name="test_password_export_collision_preserves_existing_output[tgwpw]" file="tools/test_password_export.py" line="261" time="0.237" /><testcase classname="tools.test_password_export" name="test_export_cleanup_removes_only_known_temporary_export_names" file="tools/test_password_export.py" line="273" time="0.002" /><testcase classname="tools.test_paused_updates" name="test_connected_client_is_rewound_to_the_position_saved_at_pause" file="tools/test_paused_updates.py" line="38" time="0.001" /><testcase classname="tools.test_paused_updates" name="test_disconnected_client_still_rewinds_its_session" file="tools/test_paused_updates.py" line="46" time="0.000" /><testcase classname="tools.test_paused_updates" name="test_missing_saved_position_reports_unrecoverable_drops" file="tools/test_paused_updates.py" line="52" time="0.000" /><testcase classname="tools.test_paused_updates" name="test_saved_position_of_another_account_is_not_used" file="tools/test_paused_updates.py" line="58" time="0.000" /><testcase classname="tools.test_paused_updates" name="test_no_drops_leaves_connection_untouched" file="tools/test_paused_updates.py" line="64" time="0.000" /><testcase classname="tools.test_pending_login_revocation" name="test_pending_qr_follows_its_access_session[logout]" file="tools/test_pending_login_revocation.py" line="9" time="0.741" /><testcase classname="tools.test_pending_login_revocation" name="test_pending_qr_follows_its_access_session[revoke]" file="tools/test_pending_login_revocation.py" line="9" time="0.723" /><testcase classname="tools.test_pending_login_revocation" name="test_pending_qr_follows_its_access_session[end]" file="tools/test_pending_login_revocation.py" line="9" time="0.688" /><testcase classname="tools.test_pending_login_revocation" name="test_pending_qr_follows_its_access_session[rotate]" file="tools/test_pending_login_revocation.py" line="9" time="2.034" /><testcase classname="tools.test_pending_login_revocation" name="test_pending_qr_follows_its_access_session[rotate-direct]" file="tools/test_pending_login_revocation.py" line="9" time="0.775" /><testcase classname="tools.test_pending_login_revocation" name="test_pending_qr_follows_its_access_session[other-session]" file="tools/test_pending_login_revocation.py" line="9" time="0.769" /><testcase classname="tools.test_pending_login_revocation" name="test_pending_qr_follows_its_access_session[replacement]" file="tools/test_pending_login_revocation.py" line="9" time="0.761" /><testcase classname="tools.test_pending_login_revocation" name="test_pending_qr_follows_its_access_session[completed]" file="tools/test_pending_login_revocation.py" line="9" time="0.721" /><testcase classname="tools.test_pending_login_revocation" name="test_revoked_session_cannot_start_a_queued_qr_login" file="tools/test_pending_login_revocation.py" line="67" time="0.650" /><testcase classname="tools.test_persona" name="test_reads_profile_every_privacy_setting_with_exceptions_and_account_options" file="tools/test_persona.py" line="128" time="0.157" /><testcase classname="tools.test_persona" name="test_updates_only_the_fields_the_operator_changed" file="tools/test_persona.py" line="151" time="0.169" /><testcase classname="tools.test_persona" name="test_username_can_be_removed_and_unchanged_values_send_nothing" file="tools/test_persona.py" line="163" time="0.203" /><testcase classname="tools.test_persona" name="test_taken_username_is_refused_before_any_change" file="tools/test_persona.py" line="173" time="0.167" /><testcase classname="tools.test_persona" name="test_invalid_profile_requests[body0]" file="tools/test_persona.py" line="180" time="0.001" /><testcase classname="tools.test_persona" name="test_invalid_profile_requests[body1]" file="tools/test_persona.py" line="180" time="0.001" /><testcase classname="tools.test_persona" name="test_invalid_profile_requests[body2]" file="tools/test_persona.py" line="180" time="0.001" /><testcase classname="tools.test_persona" name="test_invalid_profile_requests[body3]" file="tools/test_persona.py" line="180" time="0.001" /><testcase classname="tools.test_persona" name="test_invalid_profile_requests[body4]" file="tools/test_persona.py" line="180" time="0.001" /><testcase classname="tools.test_persona" name="test_invalid_profile_requests[body5]" file="tools/test_persona.py" line="180" time="0.001" /><testcase classname="tools.test_persona" name="test_invalid_profile_requests[body6]" file="tools/test_persona.py" line="180" time="0.001" /><testcase classname="tools.test_persona" name="test_sets_each_chosen_privacy_value_and_keeps_existing_exceptions" file="tools/test_persona.py" line="187" time="0.176" /><testcase classname="tools.test_persona" name="test_exception_lists_can_be_replaced_by_username_or_known_person" file="tools/test_persona.py" line="208" time="0.189" /><testcase classname="tools.test_persona" name="test_unknown_people_stop_only_their_setting" file="tools/test_persona.py" line="226" time="0.178" /><testcase classname="tools.test_persona" name="test_privacy_is_not_changed_when_an_exception_cannot_be_kept" file="tools/test_persona.py" line="234" time="0.173" /><testcase classname="tools.test_persona" name="test_privacy_failures_are_reported_and_flood_waits_stop" file="tools/test_persona.py" line="245" time="0.181" /><testcase classname="tools.test_persona" name="test_invalid_privacy_requests[rules0]" file="tools/test_persona.py" line="255" time="0.000" /><testcase classname="tools.test_persona" name="test_invalid_privacy_requests[rules1]" file="tools/test_persona.py" line="255" time="0.000" /><testcase classname="tools.test_persona" name="test_invalid_privacy_requests[rules2]" file="tools/test_persona.py" line="255" time="0.000" /><testcase classname="tools.test_persona" name="test_invalid_privacy_requests[rules3]" file="tools/test_persona.py" line="255" time="0.000" /><testcase classname="tools.test_persona" name="test_invalid_privacy_requests[rules4]" file="tools/test_persona.py" line="255" time="0.000" /><testcase classname="tools.test_persona" name="test_invalid_privacy_requests[rules5]" file="tools/test_persona.py" line="255" time="0.000" /><testcase classname="tools.test_persona" name="test_invalid_privacy_requests[rules6]" file="tools/test_persona.py" line="255" time="0.000" /><testcase classname="tools.test_persona" name="test_account_wide_options_change_only_what_was_chosen" file="tools/test_persona.py" line="265" time="0.232" /><testcase classname="tools.test_persona" name="test_avatar_is_uploaded_unchanged_and_recorded[PNG-image/png]" file="tools/test_persona.py" line="279" time="0.254" /><testcase classname="tools.test_persona" name="test_avatar_is_uploaded_unchanged_and_recorded[JPEG-image/jpeg]" file="tools/test_persona.py" line="279" time="0.236" /><testcase classname="tools.test_persona" name="test_avatar_rejects_other_files[not an image at all]" file="tools/test_persona.py" line="290" time="0.259" /><testcase classname="tools.test_persona" name="test_avatar_rejects_other_files[data1]" file="tools/test_persona.py" line="290" time="0.237" /><testcase classname="tools.test_persona" name="test_current_photo_is_shown_and_can_be_removed" file="tools/test_persona.py" line="299" time="0.236" /><testcase classname="tools.test_persona" name="test_changes_respect_read_only_and_evidence_goal" file="tools/test_persona.py" line="311" time="0.241" /><testcase classname="tools.test_persona" name="test_avatar_body_limit" file="tools/test_persona.py" line="325" time="0.000" /><testcase classname="tools.test_presence_watch" name="test_accounts_are_watched_by_id_or_username_without_duplicates" file="tools/test_presence_watch.py" line="53" time="0.251" /><testcase classname="tools.test_presence_watch" name="test_invalid_watches[body0]" file="tools/test_presence_watch.py" line="68" time="0.001" /><testcase classname="tools.test_presence_watch" name="test_invalid_watches[body1]" file="tools/test_presence_watch.py" line="68" time="0.001" /><testcase classname="tools.test_presence_watch" name="test_invalid_watches[body2]" file="tools/test_presence_watch.py" line="68" time="0.001" /><testcase classname="tools.test_presence_watch" name="test_invalid_watches[body3]" file="tools/test_presence_watch.py" line="68" time="0.001" /><testcase classname="tools.test_presence_watch" name="test_the_check_interval_is_bounded[30]" file="tools/test_presence_watch.py" line="74" time="0.001" /><testcase classname="tools.test_presence_watch" name="test_the_check_interval_is_bounded[3601]" file="tools/test_presence_watch.py" line="74" time="0.001" /><testcase classname="tools.test_presence_watch" name="test_the_interval_is_recorded_and_defaults_to_five_minutes" file="tools/test_presence_watch.py" line="80" time="0.231" /><testcase classname="tools.test_presence_watch" name="test_one_batched_request_covers_every_watch_and_only_changes_are_recorded" file="tools/test_presence_watch.py" line="87" time="0.312" /><testcase classname="tools.test_presence_watch" name="test_unchanged_states_can_be_recorded_on_purpose" file="tools/test_presence_watch.py" line="108" time="0.290" /><testcase classname="tools.test_presence_watch" name="test_accounts_telegram_will_not_resolve_are_reported_not_hidden" file="tools/test_presence_watch.py" line="117" time="0.251" /><testcase classname="tools.test_presence_watch" name="test_the_pattern_counts_hours_in_the_chosen_zone_and_builds_sessions" file="tools/test_presence_watch.py" line="126" time="0.288" /><testcase classname="tools.test_presence_watch" name="test_watching_is_off_for_the_evidence_goal" file="tools/test_presence_watch.py" line="139" time="0.237" /><testcase classname="tools.test_presence_watch" name="test_the_protocol_reads_the_change_in_plain_words" file="tools/test_presence_watch.py" line="147" time="0.269" /><testcase classname="tools.test_provider_metadata_umask" name="test_metadata_directory_respects_creation_and_existing_permissions[False]" file="tools/test_provider_metadata_umask.py" line="7" time="0.001" /><testcase classname="tools.test_provider_metadata_umask" name="test_metadata_directory_respects_creation_and_existing_permissions[True]" file="tools/test_provider_metadata_umask.py" line="7" time="0.001" /><testcase classname="tools.test_publication_guard" name="test_isolated_cli_checks_the_index_and_rejects_unstaged_changes" file="tools/test_publication_guard.py" line="49" time="0.263" /><testcase classname="tools.test_publication_guard" name="test_isolated_file_import_preserves_search_paths_and_ignores_preloaded_names" file="tools/test_publication_guard.py" line="67" time="0.067" /><testcase classname="tools.test_publication_guard" name="test_package_import_uses_the_package_source_builder" file="tools/test_publication_guard.py" line="91" time="0.067" /><testcase classname="tools.test_qr_codes" name="test_a_payment_code_becomes_a_wallet_and_a_payment_link" file="tools/test_qr_codes.py" line="45" time="0.000"><skipped type="pytest.skip" message="OpenCV is not installed">/workspace/qa/src/db86ca0b4e82515795ccc1c5e32a55579582c0fe/tools/test_qr_codes.py:46: OpenCV is not installed</skipped></testcase><testcase classname="tools.test_qr_codes" name="test_images_are_scanned_once_and_only_in_the_chosen_chat" file="tools/test_qr_codes.py" line="61" time="0.000"><skipped type="pytest.skip" message="OpenCV is not installed">/workspace/qa/src/db86ca0b4e82515795ccc1c5e32a55579582c0fe/tools/test_qr_codes.py:62: OpenCV is not installed</skipped></testcase><testcase classname="tools.test_qr_codes" name="test_pictures_without_a_code_and_broken_files_are_reported" file="tools/test_qr_codes.py" line="73" time="0.000"><skipped type="pytest.skip" message="OpenCV is not installed">/workspace/qa/src/db86ca0b4e82515795ccc1c5e32a55579582c0fe/tools/test_qr_codes.py:74: OpenCV is not installed</skipped></testcase><testcase classname="tools.test_qr_codes" name="test_videos_and_voice_files_are_never_scanned" file="tools/test_qr_codes.py" line="88" time="0.227" /><testcase classname="tools.test_qr_codes" name="test_a_missing_reader_is_said_plainly" file="tools/test_qr_codes.py" line="95" time="0.206" /><testcase classname="tools.test_qr_codes" name="test_the_protocol_shows_the_code_with_its_honest_caveat" file="tools/test_qr_codes.py" line="104" time="0.000"><skipped type="pytest.skip" message="OpenCV is not installed">/workspace/qa/src/db86ca0b4e82515795ccc1c5e32a55579582c0fe/tools/test_qr_codes.py:105: OpenCV is not installed</skipped></testcase><testcase classname="tools.test_release_branch_fixes" name="test_installer_runtime_lock_is_hash_pinned" file="tools/test_release_branch_fixes.py" line="13" time="0.002" /><testcase classname="tools.test_release_branch_fixes" name="test_installer_rejects_unpinned_or_unhashed_dependencies[content0]" file="tools/test_release_branch_fixes.py" line="19" time="0.001" /><testcase classname="tools.test_release_branch_fixes" name="test_installer_rejects_unpinned_or_unhashed_dependencies[content1]" file="tools/test_release_branch_fixes.py" line="19" time="0.001" /><testcase classname="tools.test_release_branch_fixes" name="test_installer_rejects_unpinned_or_unhashed_dependencies[first&gt;=1\n    --hash=sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n]" file="tools/test_release_branch_fixes.py" line="19" time="0.001" /><testcase classname="tools.test_release_branch_fixes" name="test_installer_rejects_unpinned_or_unhashed_dependencies[content3]" file="tools/test_release_branch_fixes.py" line="19" time="0.001" /><testcase classname="tools.test_release_branch_fixes" name="test_installer_rejects_unpinned_or_unhashed_dependencies[first==1\n    --hash=md5:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n]" file="tools/test_release_branch_fixes.py" line="19" time="0.001" /><testcase classname="tools.test_release_branch_fixes" name="test_installer_rejects_unpinned_or_unhashed_dependencies[    --hash=sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\nfirst==1\n]" file="tools/test_release_branch_fixes.py" line="19" time="0.001" /><testcase classname="tools.test_release_branch_fixes" name="test_reference_source_requires_consent_and_scrubs_credentials[https://github.com/phishdestroy/TgWitness.git-False-True]" file="tools/test_release_branch_fixes.py" line="35" time="0.001" /><testcase classname="tools.test_release_branch_fixes" name="test_reference_source_requires_consent_and_scrubs_credentials[https://github.com/phishdestroy/TgWitness-False-True]" file="tools/test_release_branch_fixes.py" line="35" time="0.001" /><testcase classname="tools.test_release_branch_fixes" name="test_reference_source_requires_consent_and_scrubs_credentials[https://github.com/example/fictional.git-False-False]" file="tools/test_release_branch_fixes.py" line="35" time="0.001" /><testcase classname="tools.test_release_branch_fixes" name="test_reference_source_requires_consent_and_scrubs_credentials[https://github.com/example/fictional.git-True-True]" file="tools/test_release_branch_fixes.py" line="35" time="0.001" /><testcase classname="tools.test_release_branch_fixes" name="test_cloud_verify_exposes_explicit_source_consent" file="tools/test_release_branch_fixes.py" line="66" time="0.002" /><testcase classname="tools.test_release_branch_fixes" name="test_cached_provider_record_does_not_query_metadata" file="tools/test_release_branch_fixes.py" line="73" time="0.001" /><testcase classname="tools.test_release_branch_fixes" name="test_missing_or_wrong_provider_cache_uses_existing_fallback[None]" file="tools/test_release_branch_fixes.py" line="83" time="0.001" /><testcase classname="tools.test_release_branch_fixes" name="test_missing_or_wrong_provider_cache_uses_existing_fallback[{]" file="tools/test_release_branch_fixes.py" line="83" time="0.001" /><testcase classname="tools.test_release_branch_fixes" name="test_missing_or_wrong_provider_cache_uses_existing_fallback[[]]" file="tools/test_release_branch_fixes.py" line="83" time="0.001" /><testcase classname="tools.test_release_branch_fixes" name="test_missing_or_wrong_provider_cache_uses_existing_fallback[{&quot;provider&quot;:&quot;hetzner&quot;}]" file="tools/test_release_branch_fixes.py" line="83" time="0.001" /><testcase classname="tools.test_release_branch_fixes" name="test_provider_cache_is_replaced_and_readable_by_collector" file="tools/test_release_branch_fixes.py" line="95" time="0.001" /><testcase classname="tools.test_release_branch_fixes" name="test_cloud_service_separates_metadata_and_tunnel_secrets" file="tools/test_release_branch_fixes.py" line="107" time="0.000" /><testcase classname="tools.test_release_branch_fixes" name="test_local_tunnel_credentials_only_reach_owned_listener[12345]" file="tools/test_release_branch_fixes.py" line="127" time="0.015" /><testcase classname="tools.test_release_branch_fixes" name="test_local_tunnel_credentials_only_reach_owned_listener[54321]" file="tools/test_release_branch_fixes.py" line="127" time="0.014" /><testcase classname="tools.test_release_branch_fixes" name="test_local_tunnel_credentials_only_reach_owned_listener[None]" file="tools/test_release_branch_fixes.py" line="127" time="0.014" /><testcase classname="tools.test_release_data_fixes" name="test_signed_handover_projects_actions_and_chat_titles[False-classic]" file="tools/test_release_data_fixes.py" line="112" time="0.998" /><testcase classname="tools.test_release_data_fixes" name="test_signed_handover_projects_actions_and_chat_titles[False-quire]" file="tools/test_release_data_fixes.py" line="112" time="2.492" /><testcase classname="tools.test_release_data_fixes" name="test_signed_handover_projects_actions_and_chat_titles[False-meridian]" file="tools/test_release_data_fixes.py" line="112" time="1.019" /><testcase classname="tools.test_release_data_fixes" name="test_signed_handover_projects_actions_and_chat_titles[False-atlas]" file="tools/test_release_data_fixes.py" line="112" time="1.002" /><testcase classname="tools.test_release_data_fixes" name="test_signed_handover_projects_actions_and_chat_titles[False-ledger]" file="tools/test_release_data_fixes.py" line="112" time="1.028" /><testcase classname="tools.test_release_data_fixes" name="test_signed_handover_projects_actions_and_chat_titles[False-horizon]" file="tools/test_release_data_fixes.py" line="112" time="0.996" /><testcase classname="tools.test_release_data_fixes" name="test_signed_handover_projects_actions_and_chat_titles[False-reading_series]" file="tools/test_release_data_fixes.py" line="112" time="1.050" /><testcase classname="tools.test_release_data_fixes" name="test_signed_handover_projects_actions_and_chat_titles[False-ledger_margin]" file="tools/test_release_data_fixes.py" line="112" time="2.029" /><testcase classname="tools.test_release_data_fixes" name="test_signed_handover_projects_actions_and_chat_titles[False-profile_overview]" file="tools/test_release_data_fixes.py" line="112" time="0.990" /><testcase classname="tools.test_release_data_fixes" name="test_signed_handover_projects_actions_and_chat_titles[True-classic]" file="tools/test_release_data_fixes.py" line="112" time="0.998" /><testcase classname="tools.test_release_data_fixes" name="test_signed_handover_projects_actions_and_chat_titles[True-quire]" file="tools/test_release_data_fixes.py" line="112" time="1.165" /><testcase classname="tools.test_release_data_fixes" name="test_signed_handover_projects_actions_and_chat_titles[True-meridian]" file="tools/test_release_data_fixes.py" line="112" time="1.094" /><testcase classname="tools.test_release_data_fixes" name="test_signed_handover_projects_actions_and_chat_titles[True-atlas]" file="tools/test_release_data_fixes.py" line="112" time="2.051" /><testcase classname="tools.test_release_data_fixes" name="test_signed_handover_projects_actions_and_chat_titles[True-ledger]" file="tools/test_release_data_fixes.py" line="112" time="1.035" /><testcase classname="tools.test_release_data_fixes" name="test_signed_handover_projects_actions_and_chat_titles[True-horizon]" file="tools/test_release_data_fixes.py" line="112" time="0.937" /><testcase classname="tools.test_release_data_fixes" name="test_signed_handover_projects_actions_and_chat_titles[True-reading_series]" file="tools/test_release_data_fixes.py" line="112" time="1.577" /><testcase classname="tools.test_release_data_fixes" name="test_signed_handover_projects_actions_and_chat_titles[True-ledger_margin]" file="tools/test_release_data_fixes.py" line="112" time="1.005" /><testcase classname="tools.test_release_data_fixes" name="test_signed_handover_projects_actions_and_chat_titles[True-profile_overview]" file="tools/test_release_data_fixes.py" line="112" time="0.954" /><testcase classname="tools.test_release_data_fixes" name="test_interaction_content_follows_author_policy[none-subjects0-pseudonymize-False-False]" file="tools/test_release_data_fixes.py" line="149" time="0.295" /><testcase classname="tools.test_release_data_fixes" name="test_interaction_content_follows_author_policy[subjects-subjects1-pseudonymize-True-False]" file="tools/test_release_data_fixes.py" line="149" time="0.460" /><testcase classname="tools.test_release_data_fixes" name="test_interaction_content_follows_author_policy[subjects-subjects2-pseudonymize-True-True]" file="tools/test_release_data_fixes.py" line="149" time="0.448" /><testcase classname="tools.test_release_data_fixes" name="test_interaction_content_follows_author_policy[all-subjects3-pseudonymize-True-True]" file="tools/test_release_data_fixes.py" line="149" time="0.296" /><testcase classname="tools.test_release_data_fixes" name="test_interaction_content_follows_author_policy[all-subjects4-omit-True-False]" file="tools/test_release_data_fixes.py" line="149" time="0.253" /><testcase classname="tools.test_release_data_fixes" name="test_allowed_action_text_and_contacts_are_retained" file="tools/test_release_data_fixes.py" line="172" time="0.271" /><testcase classname="tools.test_release_data_fixes" name="test_actions_outside_selected_period_do_not_restore_text" file="tools/test_release_data_fixes.py" line="180" time="0.314" /><testcase classname="tools.test_release_data_fixes" name="test_unknown_interaction_fields_are_not_copied" file="tools/test_release_data_fixes.py" line="190" time="0.326" /><testcase classname="tools.test_release_data_fixes" name="test_recovered_messages_are_signed_by_the_actual_fetcher[recovered0]" file="tools/test_release_data_fixes.py" line="303" time="2.652" /><testcase classname="tools.test_release_data_fixes" name="test_recovered_messages_are_signed_by_the_actual_fetcher[recovered1]" file="tools/test_release_data_fixes.py" line="303" time="1.581" /><testcase classname="tools.test_release_data_fixes" name="test_recovered_messages_are_signed_by_the_actual_fetcher[recovered2]" file="tools/test_release_data_fixes.py" line="303" time="1.805" /><testcase classname="tools.test_release_data_fixes" name="test_failed_final_verification_never_publishes_ready_archive" file="tools/test_release_data_fixes.py" line="331" time="3.325" /><testcase classname="tools.test_release_data_fixes" name="test_invalid_recheck_ids_fail_closed[recovered0]" file="tools/test_release_data_fixes.py" line="337" time="1.467" /><testcase classname="tools.test_release_data_fixes" name="test_invalid_recheck_ids_fail_closed[recovered1]" file="tools/test_release_data_fixes.py" line="337" time="2.247" /><testcase classname="tools.test_release_data_fixes" name="test_invalid_recheck_ids_fail_closed[recovered2]" file="tools/test_release_data_fixes.py" line="337" time="2.787" /><testcase classname="tools.test_release_data_fixes" name="test_recheck_error_keeps_the_original_signed_ranges" file="tools/test_release_data_fixes.py" line="348" time="3.337" /><testcase classname="tools.test_release_data_fixes" name="test_selection_rejects_changed_original_fetch" file="tools/test_release_data_fixes.py" line="355" time="1.429" /><testcase classname="tools.test_removal_notice_order" name="test_removal_notice_is_recorded_before_access_check_can_fail" file="tools/test_removal_notice_order.py" line="51" time="0.001" /><testcase classname="tools.test_removal_notice_order" name="test_removal_is_recorded_without_resolving_the_lost_chat" file="tools/test_removal_notice_order.py" line="58" time="0.000" /><testcase classname="tools.test_removal_notice_order" name="test_access_is_checked_even_when_membership_messages_are_not_recorded" file="tools/test_removal_notice_order.py" line="64" time="0.000" /><testcase classname="tools.test_removal_notice_order" name="test_recovered_duplicate_is_not_recorded_twice_but_access_is_checked" file="tools/test_removal_notice_order.py" line="70" time="0.001" /><testcase classname="tools.test_removal_notice_order" name="test_another_member_leaving_uses_normal_scope_check" file="tools/test_removal_notice_order.py" line="79" time="0.000" /><testcase classname="tools.test_render_boundary" name="test_detached_values_preserve_shape_without_source_aliases" file="tools/test_render_boundary.py" line="31" time="0.000" /><testcase classname="tools.test_render_boundary" name="test_stream_copies_one_record_at_a_time_and_preserves_reiteration" file="tools/test_render_boundary.py" line="44" time="0.000" /><testcase classname="tools.test_render_boundary" name="test_context_preserves_signing_capability_without_copying_its_owner" file="tools/test_render_boundary.py" line="63" time="0.000" /><testcase classname="tools.test_render_boundary" name="test_promoted_render_sections_keep_translation_keys" file="tools/test_render_boundary.py" line="76" time="0.092" /><testcase classname="tools.test_render_boundary" name="test_renderer_mutation_cannot_change_signed_input[evidence_html]" file="tools/test_render_boundary.py" line="83" time="0.002" /><testcase classname="tools.test_render_boundary" name="test_renderer_mutation_cannot_change_signed_input[chat_html]" file="tools/test_render_boundary.py" line="83" time="0.002" /><testcase classname="tools.test_render_boundary" name="test_renderer_mutation_cannot_change_signed_input[evidence_pdf]" file="tools/test_render_boundary.py" line="83" time="0.002" /><testcase classname="tools.test_render_boundary" name="test_renderer_mutation_cannot_change_signed_input[chat_pdf]" file="tools/test_render_boundary.py" line="83" time="0.002" /><testcase classname="tools.test_render_boundary" name="test_report_data_detaches_source_streams_and_assessment_context" file="tools/test_render_boundary.py" line="130" time="0.001" /><testcase classname="tools.test_replica_derivation" name="test_v2_key_matches_hkdf_and_separates_workspaces" file="tools/test_replica_derivation.py" line="19" time="0.000" /><testcase classname="tools.test_replica_derivation" name="test_restore_rejects_unknown_derivation_and_invalid_fingerprint_before_storage[v3-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa]" file="tools/test_replica_derivation.py" line="33" time="0.001" /><testcase classname="tools.test_replica_derivation" name="test_restore_rejects_unknown_derivation_and_invalid_fingerprint_before_storage[None-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa]" file="tools/test_replica_derivation.py" line="33" time="0.001" /><testcase classname="tools.test_replica_derivation" name="test_restore_rejects_unknown_derivation_and_invalid_fingerprint_before_storage[v2-not-a-fingerprint]" file="tools/test_replica_derivation.py" line="33" time="0.001" /><testcase classname="tools.test_replica_derivation" name="test_restore_rejects_unknown_derivation_and_invalid_fingerprint_before_storage[v1-AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA]" file="tools/test_replica_derivation.py" line="33" time="0.001" /><testcase classname="tools.test_replica_derivation" name="test_migration_keeps_old_objects_and_restores_both_key_files[False]" file="tools/test_replica_derivation.py" line="47" time="0.478" /><testcase classname="tools.test_replica_derivation" name="test_migration_keeps_old_objects_and_restores_both_key_files[True]" file="tools/test_replica_derivation.py" line="47" time="0.394" /><testcase classname="tools.test_replica_derivation" name="test_replica_connection_probe_uses_current_workspace_key" file="tools/test_replica_derivation.py" line="124" time="0.731" /><testcase classname="tools.test_replica_recipient" name="test_recipient_roundtrip_and_legacy[0]" file="tools/test_replica_recipient.py" line="32" time="0.003" /><testcase classname="tools.test_replica_recipient" name="test_recipient_roundtrip_and_legacy[17]" file="tools/test_replica_recipient.py" line="32" time="0.002" /><testcase classname="tools.test_replica_recipient" name="test_recipient_roundtrip_and_legacy[1048576]" file="tools/test_replica_recipient.py" line="32" time="0.008" /><testcase classname="tools.test_replica_recipient" name="test_recipient_roundtrip_and_legacy[1048589]" file="tools/test_replica_recipient.py" line="32" time="0.008" /><testcase classname="tools.test_replica_recipient" name="test_recipient_roundtrip_and_legacy[2097152]" file="tools/test_replica_recipient.py" line="32" time="0.015" /><testcase classname="tools.test_replica_recipient" name="test_each_evidence_lock_requirement_is_mandatory[False-COMPLIANCE-1]" file="tools/test_replica_recipient.py" line="57" time="0.001" /><testcase classname="tools.test_replica_recipient" name="test_each_evidence_lock_requirement_is_mandatory[None-COMPLIANCE-1]" file="tools/test_replica_recipient.py" line="57" time="0.001" /><testcase classname="tools.test_replica_recipient" name="test_each_evidence_lock_requirement_is_mandatory[True-GOVERNANCE-1]" file="tools/test_replica_recipient.py" line="57" time="0.001" /><testcase classname="tools.test_replica_recipient" name="test_each_evidence_lock_requirement_is_mandatory[True-COMPLIANCE-0]" file="tools/test_replica_recipient.py" line="57" time="0.001" /><testcase classname="tools.test_replica_recipient" name="test_invalid_public_keys_are_refused[a]" file="tools/test_replica_recipient.py" line="70" time="0.000" /><testcase classname="tools.test_replica_recipient" name="test_invalid_public_keys_are_refused[eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eA==]" file="tools/test_replica_recipient.py" line="70" time="0.000" /><testcase classname="tools.test_replica_recipient" name="test_invalid_public_keys_are_refused[AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=]" file="tools/test_replica_recipient.py" line="70" time="0.000" /><testcase classname="tools.test_replica_recipient" name="test_s3_receipt_uses_specific_version_and_never_substitutes_response_date" file="tools/test_replica_recipient.py" line="76" time="0.001" /><testcase classname="tools.test_replica_recipient" name="test_recipient_switch_has_separate_namespace" file="tools/test_replica_recipient.py" line="88" time="0.000" /><testcase classname="tools.test_replica_recipient" name="test_panel_refuses_evidence_mode_before_saving" file="tools/test_replica_recipient.py" line="96" time="0.672" /><testcase classname="tools.test_report_brief_timestamps" name="test_many_receipts_are_summarised_with_the_latest_checkpoint_and_a_folded_full_list" file="tools/test_report_brief_timestamps.py" line="25" time="0.001" /><testcase classname="tools.test_report_brief_timestamps" name="test_brief_uses_singular_forms_grouped_numbers_and_translated_plurals" file="tools/test_report_brief_timestamps.py" line="38" time="0.007" /><testcase classname="tools.test_report_brief_timestamps" name="test_missing_singular_translation_keeps_the_translated_plural_entry" file="tools/test_report_brief_timestamps.py" line="47" time="0.006" /><testcase classname="tools.test_report_brief_timestamps" name="test_absent_numbers_say_what_the_journal_knows_about_each_gap" file="tools/test_report_brief_timestamps.py" line="54" time="0.000" /><testcase classname="tools.test_report_brief_timestamps" name="test_long_lists_are_folded_and_top_level_files_stay_visible" file="tools/test_report_brief_timestamps.py" line="78" time="0.003" /><testcase classname="tools.test_report_brief_timestamps" name="test_assessment_references_are_shortened_with_a_count" file="tools/test_report_brief_timestamps.py" line="92" time="0.000" /><testcase classname="tools.test_report_brief_timestamps" name="test_assessment_counts_are_grouped_and_record_numbers_are_not" file="tools/test_report_brief_timestamps.py" line="98" time="0.006" /><testcase classname="tools.test_report_brief_timestamps" name="test_selected_data_counts_are_grouped" file="tools/test_report_brief_timestamps.py" line="115" time="0.006" /><testcase classname="tools.test_report_repeats" name="test_same_text_in_several_chats_is_grouped_once_per_message" file="tools/test_report_repeats.py" line="12" time="0.000" /><testcase classname="tools.test_report_repeats" name="test_limits_are_reported_and_the_listing_is_bounded" file="tools/test_report_repeats.py" line="39" time="0.000" /><testcase classname="tools.test_report_repeats" name="test_evidence_report_lists_texts_repeated_across_chats" file="tools/test_report_repeats.py" line="56" time="0.981" /><testcase classname="tools.test_report_settings" name="test_court_preset_shows_everything_and_cannot_drop_limits_or_references" file="tools/test_report_settings.py" line="37" time="0.308" /><testcase classname="tools.test_report_settings" name="test_briefing_drops_working_notes_and_references_but_keeps_conclusions_and_card" file="tools/test_report_settings.py" line="44" time="0.779" /><testcase classname="tools.test_report_settings" name="test_each_section_can_be_switched_off" file="tools/test_report_settings.py" line="51" time="0.350" /><testcase classname="tools.test_request_limit_slowloris" name="test_slow_bodies_are_limited_per_client_and_do_not_block_status[32]" file="tools/test_request_limit_slowloris.py" line="37" time="1.766" /><testcase classname="tools.test_request_limit_slowloris" name="test_slow_bodies_are_limited_per_client_and_do_not_block_status[4]" file="tools/test_request_limit_slowloris.py" line="37" time="1.746" /><testcase classname="tools.test_request_limit_slowloris" name="test_bodyless_requests_bypass_full_buffer_capacity[GET-headers0]" file="tools/test_request_limit_slowloris.py" line="72" time="0.001" /><testcase classname="tools.test_request_limit_slowloris" name="test_bodyless_requests_bypass_full_buffer_capacity[HEAD-headers1]" file="tools/test_request_limit_slowloris.py" line="72" time="0.001" /><testcase classname="tools.test_request_limit_slowloris" name="test_bodyless_requests_bypass_full_buffer_capacity[OPTIONS-headers2]" file="tools/test_request_limit_slowloris.py" line="72" time="0.001" /><testcase classname="tools.test_request_limit_slowloris" name="test_bodyless_requests_bypass_full_buffer_capacity[POST-headers3]" file="tools/test_request_limit_slowloris.py" line="72" time="0.001" /><testcase classname="tools.test_request_limit_slowloris" name="test_body_size_limit_is_kept_for_unframed_and_explicit_bodies[POST-headers0]" file="tools/test_request_limit_slowloris.py" line="92" time="0.001" /><testcase classname="tools.test_request_limit_slowloris" name="test_body_size_limit_is_kept_for_unframed_and_explicit_bodies[POST-headers1]" file="tools/test_request_limit_slowloris.py" line="92" time="0.001" /><testcase classname="tools.test_request_limit_slowloris" name="test_body_size_limit_is_kept_for_unframed_and_explicit_bodies[GET-headers2]" file="tools/test_request_limit_slowloris.py" line="92" time="0.001" /><testcase classname="tools.test_request_limit_slowloris" name="test_body_size_limit_is_kept_for_unframed_and_explicit_bodies[GET-headers3]" file="tools/test_request_limit_slowloris.py" line="92" time="0.001" /><testcase classname="tools.test_request_limit_slowloris" name="test_body_timeout_depends_on_path_not_authentication_header[/api/access/login-10]" file="tools/test_request_limit_slowloris.py" line="107" time="0.011" /><testcase classname="tools.test_request_limit_slowloris" name="test_body_timeout_depends_on_path_not_authentication_header[/api/demo-access-10]" file="tools/test_request_limit_slowloris.py" line="107" time="0.011" /><testcase classname="tools.test_request_limit_slowloris" name="test_body_timeout_depends_on_path_not_authentication_header[/api/archive/identity-10]" file="tools/test_request_limit_slowloris.py" line="107" time="0.011" /><testcase classname="tools.test_request_limit_slowloris" name="test_body_timeout_depends_on_path_not_authentication_header[/api/witness/head-10]" file="tools/test_request_limit_slowloris.py" line="107" time="0.011" /><testcase classname="tools.test_request_limit_slowloris" name="test_body_timeout_depends_on_path_not_authentication_header[/profiles/example/api/access/login-10]" file="tools/test_request_limit_slowloris.py" line="107" time="0.011" /><testcase classname="tools.test_request_limit_slowloris" name="test_body_timeout_depends_on_path_not_authentication_header[/mcp-8]" file="tools/test_request_limit_slowloris.py" line="107" time="0.011" /><testcase classname="tools.test_request_limit_slowloris" name="test_body_timeout_depends_on_path_not_authentication_header[/api/archive/mcp-8]" file="tools/test_request_limit_slowloris.py" line="107" time="0.011" /><testcase classname="tools.test_request_limit_slowloris" name="test_body_timeout_depends_on_path_not_authentication_header[/api/auth/import-60]" file="tools/test_request_limit_slowloris.py" line="107" time="0.011" /><testcase classname="tools.test_request_limit_slowloris" name="test_body_timeout_depends_on_path_not_authentication_header[/api/mcp-60]" file="tools/test_request_limit_slowloris.py" line="107" time="0.011" /><testcase classname="tools.test_request_limit_slowloris" name="test_body_timeout_depends_on_path_not_authentication_header[/api/integrations/mcp-60]" file="tools/test_request_limit_slowloris.py" line="107" time="0.011" /><testcase classname="tools.test_request_security" name="test_trusted_proxy_sets_https_and_secure_cookie_before_client_normalization[10.2.3.4]" file="tools/test_request_security.py" line="40" time="0.001" /><testcase classname="tools.test_request_security" name="test_trusted_proxy_sets_https_and_secure_cookie_before_client_normalization[::ffff:10.2.3.4]" file="tools/test_request_security.py" line="40" time="0.001" /><testcase classname="tools.test_request_security" name="test_trusted_proxy_sets_https_and_secure_cookie_before_client_normalization[2001:db8:1::5]" file="tools/test_request_security.py" line="40" time="0.000" /><testcase classname="tools.test_request_security" name="test_trusted_proxy_scheme_does_not_require_a_forwarded_address" file="tools/test_request_security.py" line="52" time="0.000" /><testcase classname="tools.test_request_security" name="test_untrusted_peer_cannot_spoof_https_or_a_trusted_client[198.51.100.12]" file="tools/test_request_security.py" line="61" time="0.000" /><testcase classname="tools.test_request_security" name="test_untrusted_peer_cannot_spoof_https_or_a_trusted_client[2001:db8:2::5]" file="tools/test_request_security.py" line="61" time="0.001" /><testcase classname="tools.test_request_security" name="test_untrusted_peer_cannot_spoof_https_or_a_trusted_client[unknown]" file="tools/test_request_security.py" line="61" time="0.000" /><testcase classname="tools.test_request_security" name="test_ambiguous_forwarded_scheme_is_ignored[values0]" file="tools/test_request_security.py" line="71" time="0.000" /><testcase classname="tools.test_request_security" name="test_ambiguous_forwarded_scheme_is_ignored[values1]" file="tools/test_request_security.py" line="71" time="0.000" /><testcase classname="tools.test_request_security" name="test_ambiguous_forwarded_scheme_is_ignored[values2]" file="tools/test_request_security.py" line="71" time="0.000" /><testcase classname="tools.test_request_security" name="test_ambiguous_forwarded_scheme_is_ignored[values3]" file="tools/test_request_security.py" line="71" time="0.000" /><testcase classname="tools.test_request_security" name="test_ambiguous_forwarded_scheme_is_ignored[values4]" file="tools/test_request_security.py" line="71" time="0.000" /><testcase classname="tools.test_request_security" name="test_ambiguous_forwarded_scheme_is_ignored[values5]" file="tools/test_request_security.py" line="71" time="0.000" /><testcase classname="tools.test_request_security" name="test_ambiguous_forwarded_scheme_is_ignored[values6]" file="tools/test_request_security.py" line="71" time="0.001" /><testcase classname="tools.test_request_security" name="test_ambiguous_forwarded_scheme_is_ignored[values7]" file="tools/test_request_security.py" line="71" time="0.000" /><testcase classname="tools.test_request_security" name="test_ambiguous_forwarded_scheme_is_ignored[values8]" file="tools/test_request_security.py" line="71" time="0.000" /><testcase classname="tools.test_request_security" name="test_forwarded_http_cannot_downgrade_an_existing_https_connection[10.2.3.4]" file="tools/test_request_security.py" line="82" time="0.000" /><testcase classname="tools.test_request_security" name="test_forwarded_http_cannot_downgrade_an_existing_https_connection[198.51.100.12]" file="tools/test_request_security.py" line="82" time="0.000" /><testcase classname="tools.test_request_security" name="test_nested_guards_keep_the_original_proxy_decision_and_count_once" file="tools/test_request_security.py" line="90" time="0.000" /><testcase classname="tools.test_request_security" name="test_failed_archive_or_witness_tokens_do_not_lock_out_the_panel[/api/archive/identity-/api/archive/query]" file="tools/test_request_security.py" line="99" time="0.001" /><testcase classname="tools.test_request_security" name="test_failed_archive_or_witness_tokens_do_not_lock_out_the_panel[/profiles/one/api/archive/identity-/profiles/two/api/archive/query]" file="tools/test_request_security.py" line="99" time="0.001" /><testcase classname="tools.test_request_security" name="test_failed_archive_or_witness_tokens_do_not_lock_out_the_panel[/mcp-/api/archive/identity]" file="tools/test_request_security.py" line="99" time="0.001" /><testcase classname="tools.test_request_security" name="test_failed_archive_or_witness_tokens_do_not_lock_out_the_panel[/mcp/-/api/archive/identity]" file="tools/test_request_security.py" line="99" time="0.001" /><testcase classname="tools.test_request_security" name="test_failed_archive_or_witness_tokens_do_not_lock_out_the_panel[/profiles/one/mcp-/api/archive/identity]" file="tools/test_request_security.py" line="99" time="0.001" /><testcase classname="tools.test_request_security" name="test_failed_archive_or_witness_tokens_do_not_lock_out_the_panel[/api/witness/head-/profiles/one/api/witness/head]" file="tools/test_request_security.py" line="99" time="0.001" /><testcase classname="tools.test_request_security" name="test_failed_archive_or_witness_tokens_do_not_lock_out_the_panel[/profiles/one/api/witness/head-/api/witness/head]" file="tools/test_request_security.py" line="99" time="0.001" /><testcase classname="tools.test_request_security" name="test_panel_management_routes_keep_the_panel_token_family[/api/access/login]" file="tools/test_request_security.py" line="123" time="0.001" /><testcase classname="tools.test_request_security" name="test_panel_management_routes_keep_the_panel_token_family[/api/mcp]" file="tools/test_request_security.py" line="123" time="0.001" /><testcase classname="tools.test_request_security" name="test_panel_management_routes_keep_the_panel_token_family[/api/integrations/mcp]" file="tools/test_request_security.py" line="123" time="0.001" /><testcase classname="tools.test_request_security" name="test_panel_management_routes_keep_the_panel_token_family[/profiles/one/api/mcp]" file="tools/test_request_security.py" line="123" time="0.001" /><testcase classname="tools.test_request_security" name="test_panel_management_routes_keep_the_panel_token_family[/profiles/one/api/integrations/mcp]" file="tools/test_request_security.py" line="123" time="0.001" /><testcase classname="tools.test_request_security" name="test_request_budget_remains_600_per_minute_for_each_family[/api/status-/mcp]" file="tools/test_request_security.py" line="137" time="0.015" /><testcase classname="tools.test_request_security" name="test_request_budget_remains_600_per_minute_for_each_family[/mcp-/api/status]" file="tools/test_request_security.py" line="137" time="0.014" /><testcase classname="tools.test_request_security" name="test_request_budget_remains_600_per_minute_for_each_family[/api/witness/head-/api/status]" file="tools/test_request_security.py" line="137" time="0.014" /><testcase classname="tools.test_request_security" name="test_bucket_limit_counts_address_family_pairs_and_keeps_lru_order" file="tools/test_request_security.py" line="151" time="0.107" /><testcase classname="tools.test_request_security" name="test_body_tokens_count_whatever_json_content_type_fastapi_accepts[headers0]" file="tools/test_request_security.py" line="168" time="0.001" /><testcase classname="tools.test_request_security" name="test_body_tokens_count_whatever_json_content_type_fastapi_accepts[headers1]" file="tools/test_request_security.py" line="168" time="0.001" /><testcase classname="tools.test_request_security" name="test_body_tokens_count_whatever_json_content_type_fastapi_accepts[headers2]" file="tools/test_request_security.py" line="168" time="0.001" /><testcase classname="tools.test_request_security" name="test_body_tokens_count_whatever_json_content_type_fastapi_accepts[headers3]" file="tools/test_request_security.py" line="168" time="0.001" /><testcase classname="tools.test_request_security" name="test_requests_without_credentials_do_not_lock_out[GET-headers0]" file="tools/test_request_security.py" line="181" time="0.001" /><testcase classname="tools.test_request_security" name="test_requests_without_credentials_do_not_lock_out[HEAD-headers1]" file="tools/test_request_security.py" line="181" time="0.001" /><testcase classname="tools.test_request_security" name="test_requests_without_credentials_do_not_lock_out[POST-headers2]" file="tools/test_request_security.py" line="181" time="0.001" /><testcase classname="tools.test_resolve_target" name="test_cached_target_needs_no_request" file="tools/test_resolve_target.py" line="22" time="0.000" /><testcase classname="tools.test_resolve_target" name="test_target_beyond_dialog_limit_resolves_without_listing_dialogs" file="tools/test_resolve_target.py" line="28" time="0.000" /><testcase classname="tools.test_resolve_target" name="test_unknown_entity_falls_back_to_dialog_listing" file="tools/test_resolve_target.py" line="34" time="0.000" /><testcase classname="tools.test_resolve_target" name="test_unreachable_target_still_reports_the_reason" file="tools/test_resolve_target.py" line="40" time="0.000" /><testcase classname="tools.test_rpc_diagnostics" name="test_backoff_keeps_method_wrapper_counts_and_deadline[FloodWaitError]" file="tools/test_rpc_diagnostics.py" line="21" time="0.358" /><testcase classname="tools.test_rpc_diagnostics" name="test_backoff_keeps_method_wrapper_counts_and_deadline[FloodPremiumWaitError]" file="tools/test_rpc_diagnostics.py" line="21" time="0.364" /><testcase classname="tools.test_rpc_diagnostics" name="test_nested_resolution_batch_cancellation_and_snapshot" file="tools/test_rpc_diagnostics.py" line="81" time="0.001" /><testcase classname="tools.test_scale_demo" name="test_changed_display_loses_verified_state[counter]" file="tools/test_scale_demo.py" line="82" time="0.456" /><testcase classname="tools.test_scale_demo" name="test_changed_display_loses_verified_state[excerpt]" file="tools/test_scale_demo.py" line="82" time="0.165" /><testcase classname="tools.test_scale_demo" name="test_valid_outer_signature_does_not_hide_bad_checkpoint" file="tools/test_scale_demo.py" line="97" time="0.086" /><testcase classname="tools.test_scale_demo" name="test_campaign_keeps_run_metrics_and_invalidates_changed_total" file="tools/test_scale_demo.py" line="140" time="0.193" /><testcase classname="tools.test_scale_demo" name="test_campaign_rejects_inconsistent_signed_summary[duplicate_run]" file="tools/test_scale_demo.py" line="158" time="0.091" /><testcase classname="tools.test_scale_demo" name="test_campaign_rejects_inconsistent_signed_summary[wrong_sum]" file="tools/test_scale_demo.py" line="158" time="0.094" /><testcase classname="tools.test_scale_demo" name="test_campaign_rejects_inconsistent_signed_summary[inner_signature]" file="tools/test_scale_demo.py" line="158" time="0.085" /><testcase classname="tools.test_scale_demo" name="test_campaign_rejects_inconsistent_signed_summary[worker_sum]" file="tools/test_scale_demo.py" line="158" time="0.094" /><testcase classname="tools.test_scale_demo" name="test_campaign_rejects_inconsistent_signed_summary[wrong_head]" file="tools/test_scale_demo.py" line="158" time="0.089" /><testcase classname="tools.test_scale_demo" name="test_campaign_rejects_inconsistent_signed_summary[overlap]" file="tools/test_scale_demo.py" line="158" time="0.090" /><testcase classname="tools.test_scale_demo" name="test_campaign_rejects_inconsistent_signed_summary[false_completion]" file="tools/test_scale_demo.py" line="158" time="0.089" /><testcase classname="tools.test_scale_demo" name="test_seek_uses_signed_sample_and_preserves_chain_verification" file="tools/test_scale_demo.py" line="209" time="0.200" /><testcase classname="tools.test_scale_demo" name="test_replay_uses_recorded_time_without_interpolating_counts" file="tools/test_scale_demo.py" line="230" time="0.255" /><testcase classname="tools.test_scale_demo" name="test_graph_uses_elapsed_time_and_keyboard_seeks_samples" file="tools/test_scale_demo.py" line="251" time="0.151" /><testcase classname="tools.test_scale_demo" name="test_reduced_motion_keeps_manual_inspection_and_full_hashes" file="tools/test_scale_demo.py" line="262" time="0.211" /><testcase classname="tools.test_scale_demo" name="test_copy_uses_selected_receipt_and_original_event_hash" file="tools/test_scale_demo.py" line="277" time="0.226" /><testcase classname="tools.test_scale_demo" name="test_tampered_historical_receipt_invalidates_verified_replay" file="tools/test_scale_demo.py" line="292" time="0.184" /><testcase classname="tools.test_scale_demo" name="test_verified_partial_archive_has_distinct_status" file="tools/test_scale_demo.py" line="304" time="0.089" /><testcase classname="tools.test_scale_demo" name="test_interval_rate_and_event_delta_stay_distinct_from_run_average" file="tools/test_scale_demo.py" line="317" time="0.111" /><testcase classname="tools.test_scale_demo" name="test_full_selected_signature_and_key_can_be_inspected_and_copied" file="tools/test_scale_demo.py" line="333" time="0.199" /><testcase classname="tools.test_scale_demo" name="test_verification_pack_requires_checked_metadata_and_invalidates_changes" file="tools/test_scale_demo.py" line="358" time="0.201" /><testcase classname="tools.test_scale_demo" name="test_signed_verification_pack_cannot_change_scope_or_escape_directory[wrong_key]" file="tools/test_scale_demo.py" line="383" time="0.133" /><testcase classname="tools.test_scale_demo" name="test_signed_verification_pack_cannot_change_scope_or_escape_directory[wrong_head]" file="tools/test_scale_demo.py" line="383" time="0.119" /><testcase classname="tools.test_scale_demo" name="test_signed_verification_pack_cannot_change_scope_or_escape_directory[wrong_campaign]" file="tools/test_scale_demo.py" line="383" time="0.133" /><testcase classname="tools.test_scale_demo" name="test_signed_verification_pack_cannot_change_scope_or_escape_directory[path]" file="tools/test_scale_demo.py" line="383" time="0.117" /><testcase classname="tools.test_scale_demo" name="test_signed_verification_pack_cannot_change_scope_or_escape_directory[bad_signature]" file="tools/test_scale_demo.py" line="383" time="0.113" /><testcase classname="tools.test_scale_demo" name="test_signed_verification_pack_cannot_change_scope_or_escape_directory[empty_size]" file="tools/test_scale_demo.py" line="383" time="0.135" /><testcase classname="tools.test_scale_demo" name="test_aggregate_preview_does_not_invent_deletions_or_show_excerpts" file="tools/test_scale_demo.py" line="407" time="0.127" /><testcase classname="tools.test_scale_demo" name="test_receipt_check_does_not_claim_absent_journal_checkpoints" file="tools/test_scale_demo.py" line="420" time="0.113" /><testcase classname="tools.test_scale_demo" name="test_recorded_dataset_stops_polling_and_preserves_live_default[True]" file="tools/test_scale_demo.py" line="430" time="0.205" /><testcase classname="tools.test_scale_demo" name="test_recorded_dataset_stops_polling_and_preserves_live_default[None]" file="tools/test_scale_demo.py" line="430" time="0.221" /><testcase classname="tools.test_scale_demo" name="test_recorded_dataset_stops_polling_and_preserves_live_default[true]" file="tools/test_scale_demo.py" line="430" time="0.262" /><testcase classname="tools.test_sealed_account" name="test_stop_error_still_revokes_fresh_authorization" file="tools/test_sealed_account.py" line="23" time="1.620" /><testcase classname="tools.test_sealed_account" name="test_fresh_account_capture_through_http[download-regular-phone]" file="tools/test_sealed_account.py" line="77" time="1.071" /><testcase classname="tools.test_sealed_account" name="test_fresh_account_capture_through_http[download-regular-2fa]" file="tools/test_sealed_account.py" line="77" time="1.132" /><testcase classname="tools.test_sealed_account" name="test_fresh_account_capture_through_http[download-regular-qr]" file="tools/test_sealed_account.py" line="77" time="1.075" /><testcase classname="tools.test_sealed_account" name="test_fresh_account_capture_through_http[download-regular-qr_2fa]" file="tools/test_sealed_account.py" line="77" time="1.121" /><testcase classname="tools.test_sealed_account" name="test_fresh_account_capture_through_http[download-takeout-phone]" file="tools/test_sealed_account.py" line="77" time="1.299" /><testcase classname="tools.test_sealed_account" name="test_fresh_account_capture_through_http[download-takeout-2fa]" file="tools/test_sealed_account.py" line="77" time="1.260" /><testcase classname="tools.test_sealed_account" name="test_fresh_account_capture_through_http[download-takeout-qr]" file="tools/test_sealed_account.py" line="77" time="1.234" /><testcase classname="tools.test_sealed_account" name="test_fresh_account_capture_through_http[download-takeout-qr_2fa]" file="tools/test_sealed_account.py" line="77" time="1.299" /><testcase classname="tools.test_sealed_account" name="test_fresh_account_capture_through_http[hashes_only-regular-phone]" file="tools/test_sealed_account.py" line="77" time="1.133" /><testcase classname="tools.test_sealed_account" name="test_fresh_account_capture_through_http[hashes_only-regular-2fa]" file="tools/test_sealed_account.py" line="77" time="1.474" /><testcase classname="tools.test_sealed_account" name="test_fresh_account_capture_through_http[hashes_only-regular-qr]" file="tools/test_sealed_account.py" line="77" time="1.095" /><testcase classname="tools.test_sealed_account" name="test_fresh_account_capture_through_http[hashes_only-regular-qr_2fa]" file="tools/test_sealed_account.py" line="77" time="1.010" /><testcase classname="tools.test_sealed_account" name="test_fresh_account_capture_through_http[hashes_only-takeout-phone]" file="tools/test_sealed_account.py" line="77" time="1.022" /><testcase classname="tools.test_sealed_account" name="test_fresh_account_capture_through_http[hashes_only-takeout-2fa]" file="tools/test_sealed_account.py" line="77" time="0.998" /><testcase classname="tools.test_sealed_account" name="test_fresh_account_capture_through_http[hashes_only-takeout-qr]" file="tools/test_sealed_account.py" line="77" time="1.022" /><testcase classname="tools.test_sealed_account" name="test_fresh_account_capture_through_http[hashes_only-takeout-qr_2fa]" file="tools/test_sealed_account.py" line="77" time="1.025" /><testcase classname="tools.test_sealed_account" name="test_fresh_account_capture_through_http[exclude-regular-phone]" file="tools/test_sealed_account.py" line="77" time="0.866" /><testcase classname="tools.test_sealed_account" name="test_fresh_account_capture_through_http[exclude-regular-2fa]" file="tools/test_sealed_account.py" line="77" time="0.931" /><testcase classname="tools.test_sealed_account" name="test_fresh_account_capture_through_http[exclude-regular-qr]" file="tools/test_sealed_account.py" line="77" time="1.118" /><testcase classname="tools.test_sealed_account" name="test_fresh_account_capture_through_http[exclude-regular-qr_2fa]" file="tools/test_sealed_account.py" line="77" time="1.104" /><testcase classname="tools.test_sealed_account" name="test_fresh_account_capture_through_http[exclude-takeout-phone]" file="tools/test_sealed_account.py" line="77" time="1.310" /><testcase classname="tools.test_sealed_account" name="test_fresh_account_capture_through_http[exclude-takeout-2fa]" file="tools/test_sealed_account.py" line="77" time="1.189" /><testcase classname="tools.test_sealed_account" name="test_fresh_account_capture_through_http[exclude-takeout-qr]" file="tools/test_sealed_account.py" line="77" time="1.162" /><testcase classname="tools.test_sealed_account" name="test_fresh_account_capture_through_http[exclude-takeout-qr_2fa]" file="tools/test_sealed_account.py" line="77" time="1.206" /><testcase classname="tools.test_sealed_account" name="test_deadline_during_takeout_approval_produces_partial_archive_and_revokes" file="tools/test_sealed_account.py" line="132" time="0.995" /><testcase classname="tools.test_secret_chat_custody" name="test_text_message_survives_a_journal_failure_and_is_written_once" file="tools/test_secret_chat_custody.py" line="57" time="0.338" /><testcase classname="tools.test_secret_chat_custody" name="test_already_recorded_held_message_is_released_without_a_duplicate" file="tools/test_secret_chat_custody.py" line="77" time="0.290" /><testcase classname="tools.test_secret_chat_custody" name="test_oversized_attachment_is_deferred_and_never_downloaded" file="tools/test_secret_chat_custody.py" line="86" time="0.276" /><testcase classname="tools.test_secret_chat_custody" name="test_attachment_is_deferred_when_the_disk_is_nearly_full" file="tools/test_secret_chat_custody.py" line="99" time="0.271" /><testcase classname="tools.test_secret_chat_custody" name="test_a_deferred_attachment_is_downloaded_once_space_allows" file="tools/test_secret_chat_custody.py" line="112" time="0.303" /><testcase classname="tools.test_secret_chat_custody" name="test_receiving_a_conversation_sends_no_read_typing_or_screenshot_signal" file="tools/test_secret_chat_custody.py" line="126" time="0.301" /><testcase classname="tools.test_secret_chat_custody" name="test_the_module_never_calls_a_peer_visible_acknowledgement" file="tools/test_secret_chat_custody.py" line="141" time="0.000" /><testcase classname="tools.test_secret_chat_custody" name="test_the_module_opens_no_client_connection_and_no_route_of_its_own" file="tools/test_secret_chat_custody.py" line="147" time="0.000" /><testcase classname="tools.test_secret_chat_custody" name="test_access_limited_to_selected_chats_cannot_reach_secret_chats" file="tools/test_secret_chat_custody.py" line="162" time="0.777" /><testcase classname="tools.test_secret_chat_safety" name="test_replay_after_500_later_messages_and_restart_is_not_duplicated" file="tools/test_secret_chat_safety.py" line="31" time="0.533" /><testcase classname="tools.test_secret_chat_safety" name="test_close_checks_action_policy_before_contacting_peer[True-None]" file="tools/test_secret_chat_safety.py" line="44" time="0.249" /><testcase classname="tools.test_secret_chat_safety" name="test_close_checks_action_policy_before_contacting_peer[False-evidence]" file="tools/test_secret_chat_safety.py" line="44" time="0.254" /><testcase classname="tools.test_secret_chat_safety" name="test_allowed_close_is_sent_and_journaled" file="tools/test_secret_chat_safety.py" line="62" time="0.234"><failure message="ValueError: Connect this account to Telegram first.">workspace = (&lt;tgwitness.store.Store object at 0x747f8428c2f0&gt;, &lt;tgwitness.security.Vault object at 0x747f7bae8530&gt;, &lt;tgwitness.secret_chats.SecretChats object at 0x747f7b25ba40&gt;)

    def test_allowed_close_is_sent_and_journaled(workspace):
        _, _, chats = workspace
        closed = []
    
        async def close(chat_id, reason):
            closed.append((chat_id, reason))
    
        chats.manager.close = close
&gt;       asyncio.run(chats.close(1))

tools/test_secret_chat_safety.py:71: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
/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()
           ^^^^^^^^^^^^^^^
tgwitness/secret_chats.py:572: in close
    manager = self.require()
              ^^^^^^^^^^^^^^
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = &lt;tgwitness.secret_chats.SecretChats object at 0x747f7b25ba40&gt;

    def require(self):
        if not available():
            raise ValueError(UNAVAILABLE)
        if not settings(self.store)["enabled"]:
            raise ValueError("Turn on pseudo-secret for this account first.")
        if self.manager is None or self.client is None or not self.client.is_connected():
&gt;           raise ValueError("Connect this account to Telegram first.")
E           ValueError: Connect this account to Telegram first.

tgwitness/secret_chats.py:294: ValueError</failure></testcase><testcase classname="tools.test_secret_chat_safety" name="test_failed_attachment_survives_restart_and_success_clears_it" file="tools/test_secret_chat_safety.py" line="75" time="0.294" /><testcase classname="tools.test_secret_chat_safety" name="test_cancelled_attachment_keeps_pending_work" file="tools/test_secret_chat_safety.py" line="101" time="0.249" /><testcase classname="tools.test_secret_chat_safety" name="test_journal_failure_does_not_mark_a_message_as_seen" file="tools/test_secret_chat_safety.py" line="117" time="0.259" /><testcase classname="tools.test_secret_chat_safety" name="test_attachment_can_recover_after_crash_before_message_append" file="tools/test_secret_chat_safety.py" line="133" time="0.276" /><testcase classname="tools.test_secret_chat_safety" name="test_repeated_message_while_download_runs_has_one_task" file="tools/test_secret_chat_safety.py" line="160" time="0.253" /><testcase classname="tools.test_secret_chat_safety" name="test_completed_download_retained_in_queue_is_not_repeated" file="tools/test_secret_chat_safety.py" line="191" time="0.242" /><testcase classname="tools.test_selected_export" name="test_public_selection_does_not_require_a_join_or_dialog_scan" file="tools/test_selected_export.py" line="84" time="0.029" /><testcase classname="tools.test_selected_export" name="test_selection_keeps_archive_filter[True-False-False]" file="tools/test_selected_export.py" line="97" time="0.028" /><testcase classname="tools.test_selected_export" name="test_selection_keeps_archive_filter[False-False-True]" file="tools/test_selected_export.py" line="97" time="0.029" /><testcase classname="tools.test_selected_export" name="test_selection_keeps_archive_filter[True-True-True]" file="tools/test_selected_export.py" line="97" time="0.031" /><testcase classname="tools.test_selected_export" name="test_unknown_archive_status_is_not_reported_as_unarchived" file="tools/test_selected_export.py" line="107" time="0.031" /><testcase classname="tools.test_selected_export" name="test_uncached_peer_uses_existing_dialog_inventory" file="tools/test_selected_export.py" line="114" time="0.029" /><testcase classname="tools.test_selected_export" name="test_connection_and_wait_errors_do_not_become_missing_chats[failure0]" file="tools/test_selected_export.py" line="123" time="0.026" /><testcase classname="tools.test_selected_export" name="test_connection_and_wait_errors_do_not_become_missing_chats[failure1]" file="tools/test_selected_export.py" line="123" time="0.021" /><testcase classname="tools.test_selected_export" name="test_connection_and_wait_errors_do_not_become_missing_chats[failure2]" file="tools/test_selected_export.py" line="123" time="0.022" /><testcase classname="tools.test_selected_export" name="test_connection_and_wait_errors_do_not_become_missing_chats[failure3]" file="tools/test_selected_export.py" line="123" time="0.020" /><testcase classname="tools.test_selected_export" name="test_selected_public_channel_reaches_signed_desktop_json" file="tools/test_selected_export.py" line="135" time="1.312" /><testcase classname="tools.test_selected_export" name="test_takeout_selection_keeps_split_inventory" file="tools/test_selected_export.py" line="163" time="0.033" /><testcase classname="tools.test_session_import" name="test_independent_authorization_and_provenance" file="tools/test_session_import.py" line="137" time="0.371" /><testcase classname="tools.test_session_import" name="test_resume_authorized_key_after_migration_and_interruption[after_accept]" file="tools/test_session_import.py" line="161" time="0.432" /><testcase classname="tools.test_session_import" name="test_resume_authorized_key_after_migration_and_interruption[cancel]" file="tools/test_session_import.py" line="161" time="0.421" /><testcase classname="tools.test_session_import" name="test_two_factor_prompt_imported_password_and_restart[-password]" file="tools/test_session_import.py" line="183" time="0.412" /><testcase classname="tools.test_session_import" name="test_two_factor_prompt_imported_password_and_restart[wrong-password]" file="tools/test_session_import.py" line="183" time="0.419" /><testcase classname="tools.test_session_import" name="test_two_factor_prompt_imported_password_and_restart[synthetic-password-authorized]" file="tools/test_session_import.py" line="183" time="0.356" /><testcase classname="tools.test_session_import" name="test_flood_no_retry_and_pending_workspace_ownership" file="tools/test_session_import.py" line="205" time="0.330" /><testcase classname="tools.test_session_import" name="test_restricted_account_stops_before_creating_key[frozen]" file="tools/test_session_import.py" line="227" time="0.255" /><testcase classname="tools.test_session_import" name="test_restricted_account_stops_before_creating_key[restricted]" file="tools/test_session_import.py" line="227" time="0.267" /><testcase classname="tools.test_session_import" name="test_json_two_factor_only_explicit_independent_mode" file="tools/test_session_import.py" line="242" time="0.000" /><testcase classname="tools.test_session_import" name="test_profile_import_retains_workspace_for_password_or_lost_reply[telethon-authorized]" file="tools/test_session_import.py" line="250" time="1.784" /><testcase classname="tools.test_session_import" name="test_profile_import_retains_workspace_for_password_or_lost_reply[telethon-password]" file="tools/test_session_import.py" line="250" time="1.493" /><testcase classname="tools.test_session_import" name="test_profile_import_retains_workspace_for_password_or_lost_reply[telethon-retry]" file="tools/test_session_import.py" line="250" time="1.477" /><testcase classname="tools.test_session_import" name="test_profile_import_retains_workspace_for_password_or_lost_reply[pyrogram-authorized]" file="tools/test_session_import.py" line="250" time="1.396" /><testcase classname="tools.test_session_import" name="test_profile_import_retains_workspace_for_password_or_lost_reply[pyrogram-password]" file="tools/test_session_import.py" line="250" time="3.285" /><testcase classname="tools.test_session_import" name="test_profile_import_retains_workspace_for_password_or_lost_reply[pyrogram-retry]" file="tools/test_session_import.py" line="250" time="3.240" /><testcase classname="tools.test_session_import" name="test_profile_import_retains_workspace_for_password_or_lost_reply[tdata-authorized]" file="tools/test_session_import.py" line="250" time="1.983" /><testcase classname="tools.test_session_import" name="test_profile_import_retains_workspace_for_password_or_lost_reply[tdata-password]" file="tools/test_session_import.py" line="250" time="1.777" /><testcase classname="tools.test_session_import" name="test_profile_import_retains_workspace_for_password_or_lost_reply[tdata-retry]" file="tools/test_session_import.py" line="250" time="1.865" /><testcase classname="tools.test_session_import" name="test_http_independent_login" file="tools/test_session_import.py" line="289" time="1.475" /><testcase classname="tools.test_session_import" name="test_invalid_donor_does_not_expire_saved_authorization" file="tools/test_session_import.py" line="304" time="2.064" /><testcase classname="tools.test_session_import" name="test_independent_login_browser[False]" file="tools/test_session_import.py" line="323" time="33.989"><failure message="playwright._impl._errors.TimeoutError: Locator.evaluate: Timeout 30000ms exceeded.&#10;Call log:&#10;  - waiting for locator(&quot;.other-sign-in&quot;)">workspace = &lt;tgwitness.collector.Collector object at 0x747f7ab6b110&gt;
tmp_path = PosixPath('/tmp/pytest-of-root/pytest-6/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)
&gt;               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=&gt;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 = &lt;playwright._impl._connection.Connection object at 0x747f8d32bd40&gt;
cb = &lt;function Channel.send.&lt;locals&gt;.&lt;lambda&gt; at 0x747f59328220&gt;
is_internal = False, title = None

    async def wrap_api_call(
        self, cb: Callable[[], Any], is_internal: bool = False, title: str = None
    ) -&gt; 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:
&gt;           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</failure></testcase><testcase classname="tools.test_session_import" name="test_independent_login_browser[True]" file="tools/test_session_import.py" line="323" time="34.318"><failure message="playwright._impl._errors.TimeoutError: Locator.evaluate: Timeout 30000ms exceeded.&#10;Call log:&#10;  - waiting for locator(&quot;.other-sign-in&quot;)">workspace = &lt;tgwitness.collector.Collector object at 0x747f864c7110&gt;
tmp_path = PosixPath('/tmp/pytest-of-root/pytest-6/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)
&gt;               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=&gt;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 = &lt;playwright._impl._connection.Connection object at 0x747f73446b70&gt;
cb = &lt;function Channel.send.&lt;locals&gt;.&lt;lambda&gt; at 0x747f730a6fc0&gt;
is_internal = False, title = None

    async def wrap_api_call(
        self, cb: Callable[[], Any], is_internal: bool = False, title: str = None
    ) -&gt; 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:
&gt;           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</failure></testcase><testcase classname="tools.test_site_context" name="test_deep_page_metadata_describes_configured_project" file="tools/test_site_context.py" line="14" time="0.000" /><testcase classname="tools.test_site_context" name="test_context_is_translated_and_handles_limited_language_routes" file="tools/test_site_context.py" line="31" time="0.094" /><testcase classname="tools.test_site_context" name="test_markdown_keeps_context_without_repeating_navigation" file="tools/test_site_context.py" line="45" time="0.001" /><testcase classname="tools.test_site_metadata" name="test_complete_navigation_and_unique_metadata" file="tools/test_site_metadata.py" line="43" time="0.001" /><testcase classname="tools.test_site_metadata" name="test_demo_panel_references_are_published_and_missing_dependencies_are_rejected[tgwitness/static/views/secret-chats.js]" file="tools/test_site_metadata.py" line="57" time="0.028" /><testcase classname="tools.test_site_metadata" name="test_demo_panel_references_are_published_and_missing_dependencies_are_rejected[tgwitness/static/investigate.js]" file="tools/test_site_metadata.py" line="57" time="0.036" /><testcase classname="tools.test_site_metadata" name="test_demo_panel_references_are_published_and_missing_dependencies_are_rejected[tgwitness/static/investigate.css]" file="tools/test_site_metadata.py" line="57" time="0.034" /><testcase classname="tools.test_site_metadata" name="test_collapsible_reference_renders_links_tables_and_code" file="tools/test_site_metadata.py" line="67" time="0.008" /><testcase classname="tools.test_site_metadata" name="test_collapsible_markup_in_code_remains_literal" file="tools/test_site_metadata.py" line="101" time="0.001" /><testcase classname="tools.test_site_metadata" name="test_reference_images_are_in_the_public_site_allowlist" file="tools/test_site_metadata.py" line="111" time="0.319" /><testcase classname="tools.test_site_metadata" name="test_metadata_tracks_localized_page_and_visible_hierarchy" file="tools/test_site_metadata.py" line="128" time="0.001" /><testcase classname="tools.test_site_metadata" name="test_untranslated_reference_consolidates_without_false_alternates" file="tools/test_site_metadata.py" line="149" time="0.001" /><testcase classname="tools.test_site_metadata" name="test_markdown_preserves_content_and_limits_without_site_controls" file="tools/test_site_metadata.py" line="169" time="0.001" /><testcase classname="tools.test_site_metadata" name="test_llms_index_leads_with_workflows_and_verification" file="tools/test_site_metadata.py" line="193" time="0.000" /><testcase classname="tools.test_site_seo.PageSearchMetadata" name="test_cjk_punctuation_and_localized_labels_are_retained" file="tools/test_site_seo.py" line="101" time="0.001" /><testcase classname="tools.test_site_seo.PageSearchMetadata" name="test_fullwidth_translated_brand_separator_is_not_duplicated" file="tools/test_site_seo.py" line="107" time="0.019" /><testcase classname="tools.test_site_seo.PageSearchMetadata" name="test_head_social_and_schema_agree_without_touching_evidence_examples" file="tools/test_site_seo.py" line="70" time="0.001" /><testcase classname="tools.test_site_seo.PageSearchMetadata" name="test_homepage_design_and_english_canonical_copy_are_preserved" file="tools/test_site_seo.py" line="125" time="0.001" /><testcase classname="tools.test_site_seo.PageSearchMetadata" name="test_metadata_is_escaped_and_no_unmapped_page_is_silently_published" file="tools/test_site_seo.py" line="117" time="0.001" /><testcase classname="tools.test_site_seo.PageSearchMetadata" name="test_russian_metadata_and_relative_discovery" file="tools/test_site_seo.py" line="94" time="0.001" /><testcase classname="tools.test_site_validation" name="test_rejects_measurements_that_do_not_support_claims[acquisition_records_per_second-9999]" file="tools/test_site_validation.py" line="21" time="0.001" /><testcase classname="tools.test_site_validation" name="test_rejects_measurements_that_do_not_support_claims[end_to_end_seconds-1]" file="tools/test_site_validation.py" line="21" time="0.000" /><testcase classname="tools.test_site_validation" name="test_rejects_measurements_that_do_not_support_claims[archive_verified-False]" file="tools/test_site_validation.py" line="21" time="0.000" /><testcase classname="tools.test_site_validation" name="test_rejects_measurements_that_do_not_support_claims[key_pinned-False]" file="tools/test_site_validation.py" line="21" time="0.000" /><testcase classname="tools.test_site_validation" name="test_rejects_measurements_that_do_not_support_claims[reused_records-1]" file="tools/test_site_validation.py" line="21" time="0.000" /><testcase classname="tools.test_site_validation" name="test_rejects_measurements_that_do_not_support_claims[attachments-True]" file="tools/test_site_validation.py" line="21" time="0.000" /><testcase classname="tools.test_site_validation" name="test_rejects_measurements_that_do_not_support_claims[finished_at-2099-01-01T00:00:00Z]" file="tools/test_site_validation.py" line="21" time="0.000" /><testcase classname="tools.test_site_validation" name="test_rejects_measurements_that_do_not_support_claims[acquisition_seconds-nan]" file="tools/test_site_validation.py" line="21" time="0.000" /><testcase classname="tools.test_site_validation" name="test_snapshot_preserves_unmeasured_host_and_failed_tests" file="tools/test_site_validation.py" line="38" time="0.000" /><testcase classname="tools.test_site_validation" name="test_render_keeps_data_accessible_without_javascript[en]" file="tools/test_site_validation.py" line="46" time="0.001" /><testcase classname="tools.test_site_validation" name="test_render_keeps_data_accessible_without_javascript[ru]" file="tools/test_site_validation.py" line="46" time="0.001" /><testcase classname="tools.test_site_validation" name="test_snapshot_values_cannot_inject_html" file="tools/test_site_validation.py" line="67" time="0.001" /><testcase classname="tools.test_site_validation" name="test_localized_routes_have_matching_metadata_and_downloads" file="tools/test_site_validation.py" line="77" time="0.000" /><testcase classname="tools.test_site_validation" name="test_published_audit_keeps_its_signature_and_original_bytes" file="tools/test_site_validation.py" line="87" time="0.161" /><testcase classname="tools.test_site_validation" name="test_chart_and_page_use_the_signed_measurements" file="tools/test_site_validation.py" line="108" time="0.000" /><testcase classname="tools.test_store_transactions" name="test_caught_nested_append_failure_preserves_only_complete_records[index]" file="tools/test_store_transactions.py" line="31" time="0.183" /><testcase classname="tools.test_store_transactions" name="test_caught_nested_append_failure_preserves_only_complete_records[media]" file="tools/test_store_transactions.py" line="31" time="0.194" /><testcase classname="tools.test_store_transactions" name="test_nested_group_rolls_back_settings_media_and_notifications[ValueError]" file="tools/test_store_transactions.py" line="62" time="0.181" /><testcase classname="tools.test_store_transactions" name="test_nested_group_rolls_back_settings_media_and_notifications[KeyboardInterrupt]" file="tools/test_store_transactions.py" line="62" time="0.192" /><testcase classname="tools.test_store_transactions" name="test_nested_group_rolls_back_settings_media_and_notifications[SystemExit]" file="tools/test_store_transactions.py" line="62" time="0.176" /><testcase classname="tools.test_store_transactions" name="test_nested_group_rolls_back_settings_media_and_notifications[CancelledError]" file="tools/test_store_transactions.py" line="62" time="0.189" /><testcase classname="tools.test_store_transactions" name="test_database_rollback_prevents_restarting_inside_aborted_context" file="tools/test_store_transactions.py" line="85" time="0.167" /><testcase classname="tools.test_store_transactions" name="test_outer_failure_rolls_back_successful_inner_groups" file="tools/test_store_transactions.py" line="106" time="0.187" /><testcase classname="tools.test_store_transactions" name="test_successful_nested_groups_preserve_signed_bytes_and_merkle_root" file="tools/test_store_transactions.py" line="121" time="0.346" /><testcase classname="tools.test_store_transactions" name="test_listener_can_append_after_outer_commit" file="tools/test_store_transactions.py" line="144" time="0.223" /><testcase classname="tools.test_subject" name="test_snapshot_records_labels_description_commands_and_photo" file="tools/test_subject.py" line="55" time="0.186" /><testcase classname="tools.test_subject" name="test_later_snapshot_shows_what_changed_and_ignores_parts_telegram_refused" file="tools/test_subject.py" line="68" time="0.182" /><testcase classname="tools.test_subject" name="test_protocol_and_report_show_the_card_first_and_respect_chat_scope" file="tools/test_subject.py" line="79" time="0.194" /><testcase classname="tools.test_subject" name="test_unknown_chat_is_refused" file="tools/test_subject.py" line="102" time="0.158" /><testcase classname="tools.test_subject" name="test_identical_user_snapshots_do_not_report_empty_fields_as_changes" file="tools/test_subject.py" line="113" time="0.181" /><testcase classname="tools.test_subject" name="test_first_successful_observation_after_failure_is_not_a_change[photo]" file="tools/test_subject.py" line="132" time="0.181" /><testcase classname="tools.test_subject" name="test_first_successful_observation_after_failure_is_not_a_change[full_info]" file="tools/test_subject.py" line="132" time="0.185" /><testcase classname="tools.test_system_map_pool" name="test_direct_session_inside_telegram_pool" file="tools/test_system_map_pool.py" line="16" time="0.000" /><testcase classname="tools.test_system_map_pool" name="test_proxied_session_binds_by_target_not_proxy_peer" file="tools/test_system_map_pool.py" line="22" time="0.000" /><testcase classname="tools.test_system_map_pool" name="test_ipv6_and_outside_targets" file="tools/test_system_map_pool.py" line="29" time="0.000" /><testcase classname="tools.test_system_map_pool" name="test_network_policy_counts_only_connected_sessions" file="tools/test_system_map_pool.py" line="36" time="0.000" /><testcase classname="tools.test_system_map_pool" name="test_owner_only_state_is_cached_and_failure_is_not_restricted" file="tools/test_system_map_pool.py" line="54" time="0.001" /><testcase classname="tools.test_system_map_pool" name="test_connected_account_snapshot_reports_binding_and_folder_access" file="tools/test_system_map_pool.py" line="66" time="0.001" /><testcase classname="tools.test_telegram_view_review" name="test_nested_utf16_entities_preserve_text" file="tools/test_telegram_view_review.py" line="86" time="0.000" /><testcase classname="tools.test_telegram_view_review" name="test_unsafe_links_are_plain_text[javascript:alert(1)]" file="tools/test_telegram_view_review.py" line="98" time="0.000" /><testcase classname="tools.test_telegram_view_review" name="test_unsafe_links_are_plain_text[data:text/html,evil]" file="tools/test_telegram_view_review.py" line="98" time="0.000" /><testcase classname="tools.test_telegram_view_review" name="test_unsafe_links_are_plain_text[//example.org]" file="tools/test_telegram_view_review.py" line="98" time="0.000" /><testcase classname="tools.test_telegram_view_review" name="test_unsafe_links_are_plain_text[file:///etc/passwd]" file="tools/test_telegram_view_review.py" line="98" time="0.000" /><testcase classname="tools.test_telegram_view_review" name="test_unsafe_links_are_plain_text[https://[bad]" file="tools/test_telegram_view_review.py" line="98" time="0.000" /><testcase classname="tools.test_telegram_view_review" name="test_unsafe_links_are_plain_text[https:\n//example.org]" file="tools/test_telegram_view_review.py" line="98" time="0.000" /><testcase classname="tools.test_telegram_view_review" name="test_reply_pagination_and_absent_cross_chat_target" file="tools/test_telegram_view_review.py" line="105" time="0.035" /><testcase classname="tools.test_telegram_view_review" name="test_byte_limit_paginates_and_resolves_replies" file="tools/test_telegram_view_review.py" line="127" time="0.099" /><testcase classname="tools.test_telegram_view_review" name="test_media_controls_and_download_names[video-video]" file="tools/test_telegram_view_review.py" line="139" time="0.009" /><testcase classname="tools.test_telegram_view_review" name="test_media_controls_and_download_names[voice-audio]" file="tools/test_telegram_view_review.py" line="139" time="0.008" /><testcase classname="tools.test_telegram_view_review" name="test_media_controls_and_download_names[document-a]" file="tools/test_telegram_view_review.py" line="139" time="0.008" /><testcase classname="tools.test_telegram_view_review" name="test_report_links_match_included_formats[tgwitness-False-False]" file="tools/test_telegram_view_review.py" line="159" time="0.004" /><testcase classname="tools.test_telegram_view_review" name="test_report_links_match_included_formats[telegram_html-True-False]" file="tools/test_telegram_view_review.py" line="159" time="0.002" /><testcase classname="tools.test_telegram_view_review" name="test_report_links_match_included_formats[telegram_json-False-True]" file="tools/test_telegram_view_review.py" line="159" time="0.002" /><testcase classname="tools.test_telegram_view_review" name="test_report_links_match_included_formats[telegram_both-True-True]" file="tools/test_telegram_view_review.py" line="159" time="0.001" /><testcase classname="tools.test_telegram_view_review" name="test_signed_archives_preserve_source_and_views[telegram_both]" file="tools/test_telegram_view_review.py" line="224" time="0.719" /><testcase classname="tools.test_telegram_view_review" name="test_signed_archives_preserve_source_and_views[telegram_html]" file="tools/test_telegram_view_review.py" line="224" time="0.711" /><testcase classname="tools.test_telegram_view_review" name="test_signed_archives_preserve_source_and_views[telegram_json]" file="tools/test_telegram_view_review.py" line="224" time="0.712" /><testcase classname="tools.test_telegram_view_review" name="test_signed_archives_preserve_source_and_views[tgwitness]" file="tools/test_telegram_view_review.py" line="224" time="0.695" /><testcase classname="tools.test_translation" name="test_languages_are_detected_locally_without_sending_anything" file="tools/test_translation.py" line="48" time="0.265" /><testcase classname="tools.test_translation" name="test_preview_shows_what_is_sent_and_translation_is_recorded_as_machine_output" file="tools/test_translation.py" line="57" time="0.252" /><testcase classname="tools.test_translation" name="test_only_message_records_of_the_chat_can_be_translated" file="tools/test_translation.py" line="86" time="0.252" /><testcase classname="tools.test_translation" name="test_translation_is_off_for_the_evidence_goal" file="tools/test_translation.py" line="94" time="0.254" /><testcase classname="tools.test_translation" name="test_report_shows_translation_under_the_original_and_never_for_hidden_messages" file="tools/test_translation.py" line="101" time="0.252" /><testcase classname="tools.test_translation" name="test_invalid_requests[body0]" file="tools/test_translation.py" line="123" time="0.001" /><testcase classname="tools.test_translation" name="test_invalid_requests[body1]" file="tools/test_translation.py" line="123" time="0.001" /><testcase classname="tools.test_translation" name="test_invalid_requests[body2]" file="tools/test_translation.py" line="123" time="0.001" /><testcase classname="tools.test_translation" name="test_invalid_requests[body3]" file="tools/test_translation.py" line="123" time="0.001" /><testcase classname="tools.test_translation" name="test_invalid_requests[body4]" file="tools/test_translation.py" line="123" time="0.001" /><testcase classname="tools.test_translation" name="test_preview_route_keeps_proxy_details_with_connection_permissions[None-None-True]" file="tools/test_translation.py" line="130" time="0.669" /><testcase classname="tools.test_translation" name="test_preview_route_keeps_proxy_details_with_connection_permissions[permissions1-chats1-False]" file="tools/test_translation.py" line="130" time="0.703" /><testcase classname="tools.test_translation" name="test_preview_route_keeps_proxy_details_with_connection_permissions[permissions2-None-False]" file="tools/test_translation.py" line="130" time="0.701" /><testcase classname="tools.test_translation" name="test_preview_route_keeps_proxy_details_with_connection_permissions[permissions3-chats3-False]" file="tools/test_translation.py" line="130" time="0.681" /><testcase classname="tools.test_translation" name="test_preview_route_keeps_proxy_details_with_connection_permissions[permissions4-None-True]" file="tools/test_translation.py" line="130" time="2.498" /><testcase classname="tools.test_tsa_cert_reference" name="test_reference_algorithm_is_reported_without_changing_signature_acceptance[modular-sha1]" file="tools/test_tsa_cert_reference.py" line="80" time="0.003" /><testcase classname="tools.test_tsa_cert_reference" name="test_reference_algorithm_is_reported_without_changing_signature_acceptance[modular-sha256]" file="tools/test_tsa_cert_reference.py" line="80" time="0.003" /><testcase classname="tools.test_tsa_cert_reference" name="test_reference_algorithm_is_reported_without_changing_signature_acceptance[modular-sha384]" file="tools/test_tsa_cert_reference.py" line="80" time="0.003" /><testcase classname="tools.test_tsa_cert_reference" name="test_reference_algorithm_is_reported_without_changing_signature_acceptance[modular-sha512]" file="tools/test_tsa_cert_reference.py" line="80" time="0.003" /><testcase classname="tools.test_tsa_cert_reference" name="test_reference_algorithm_is_reported_without_changing_signature_acceptance[standalone-sha1]" file="tools/test_tsa_cert_reference.py" line="80" time="0.003" /><testcase classname="tools.test_tsa_cert_reference" name="test_reference_algorithm_is_reported_without_changing_signature_acceptance[standalone-sha256]" file="tools/test_tsa_cert_reference.py" line="80" time="0.003" /><testcase classname="tools.test_tsa_cert_reference" name="test_reference_algorithm_is_reported_without_changing_signature_acceptance[standalone-sha384]" file="tools/test_tsa_cert_reference.py" line="80" time="0.002" /><testcase classname="tools.test_tsa_cert_reference" name="test_reference_algorithm_is_reported_without_changing_signature_acceptance[standalone-sha512]" file="tools/test_tsa_cert_reference.py" line="80" time="0.002" /><testcase classname="tools.test_tsa_cert_reference" name="test_reference_warning_cannot_bypass_certificate_signature_or_imprint_checks[modular-sha1]" file="tools/test_tsa_cert_reference.py" line="102" time="0.002" /><testcase classname="tools.test_tsa_cert_reference" name="test_reference_warning_cannot_bypass_certificate_signature_or_imprint_checks[modular-sha256]" file="tools/test_tsa_cert_reference.py" line="102" time="0.002" /><testcase classname="tools.test_tsa_cert_reference" name="test_reference_warning_cannot_bypass_certificate_signature_or_imprint_checks[standalone-sha1]" file="tools/test_tsa_cert_reference.py" line="102" time="0.001" /><testcase classname="tools.test_tsa_cert_reference" name="test_reference_warning_cannot_bypass_certificate_signature_or_imprint_checks[standalone-sha256]" file="tools/test_tsa_cert_reference.py" line="102" time="0.001" /><testcase classname="tools.test_tsa_cert_reference" name="test_archive_json_and_console_expose_reference_without_claiming_unchecked_signature[modular-sha1]" file="tools/test_tsa_cert_reference.py" line="117" time="0.042" /><testcase classname="tools.test_tsa_cert_reference" name="test_archive_json_and_console_expose_reference_without_claiming_unchecked_signature[modular-sha256]" file="tools/test_tsa_cert_reference.py" line="117" time="0.035" /><testcase classname="tools.test_tsa_cert_reference" name="test_archive_json_and_console_expose_reference_without_claiming_unchecked_signature[standalone-sha1]" file="tools/test_tsa_cert_reference.py" line="117" time="0.034" /><testcase classname="tools.test_tsa_cert_reference" name="test_archive_json_and_console_expose_reference_without_claiming_unchecked_signature[standalone-sha256]" file="tools/test_tsa_cert_reference.py" line="117" time="0.038" /><testcase classname="tools.test_tsa_cert_reference" name="test_reporting_propagates_warning_but_attestation_seal_keeps_original_payload" file="tools/test_tsa_cert_reference.py" line="148" time="0.028" /><testcase classname="tools.test_tsa_cert_reference" name="test_recorded_timestamp_vectors_still_verify[modular]" file="tools/test_tsa_cert_reference.py" line="172" time="0.007" /><testcase classname="tools.test_tsa_cert_reference" name="test_recorded_timestamp_vectors_still_verify[standalone]" file="tools/test_tsa_cert_reference.py" line="172" time="0.006" /><testcase classname="tools.test_undercover" name="test_personas_and_authorisations_are_recorded_in_the_journal" file="tools/test_undercover.py" line="37" time="0.336" /><testcase classname="tools.test_undercover" name="test_conversations_are_counted_by_the_gap_and_the_first_contact_is_marked" file="tools/test_undercover.py" line="57" time="0.001" /><testcase classname="tools.test_undercover" name="test_messages_outside_an_authorisation_and_without_an_operator_are_flagged" file="tools/test_undercover.py" line="70" time="0.001" /><testcase classname="tools.test_undercover" name="test_ai_assisted_messages_and_persona_changes_appear_in_the_record" file="tools/test_undercover.py" line="84" time="0.001" /><testcase classname="tools.test_undercover" name="test_invalid_authorisations[body0]" file="tools/test_undercover.py" line="95" time="0.001" /><testcase classname="tools.test_undercover" name="test_invalid_authorisations[body1]" file="tools/test_undercover.py" line="95" time="0.001" /><testcase classname="tools.test_undercover" name="test_invalid_authorisations[body2]" file="tools/test_undercover.py" line="95" time="0.001" /><testcase classname="tools.test_undercover" name="test_invalid_authorisations[body3]" file="tools/test_undercover.py" line="95" time="0.001" /><testcase classname="tools.test_undercover" name="test_invalid_authorisations[body4]" file="tools/test_undercover.py" line="95" time="0.001" /><testcase classname="tools.test_verification_launcher" name="test_launcher_and_instructions_are_signed_and_renamed_archives_are_found" file="tools/test_verification_launcher.py" line="45" time="0.382" /><testcase classname="tools.test_verification_launcher" name="test_blank_fingerprint_is_unconfirmed_and_saves_utf8_transcript[en-missing: confirmed signer key]" file="tools/test_verification_launcher.py" line="63" time="0.509" /><testcase classname="tools.test_verification_launcher" name="test_blank_fingerprint_is_unconfirmed_and_saves_utf8_transcript[ru-\u043d\u0435 \u0445\u0432\u0430\u0442\u0430\u0435\u0442: \u0441\u0432\u0435\u0440\u0435\u043d\u043d\u043e\u0433\u043e \u043a\u043b\u044e\u0447\u0430 \u043f\u043e\u0434\u043f\u0438\u0441\u0430\u043d\u0442\u0430]" file="tools/test_verification_launcher.py" line="63" time="0.449" /><testcase classname="tools.test_verification_launcher" name="test_blank_fingerprint_is_unconfirmed_and_saves_utf8_transcript[uk-\u0432\u0456\u0434\u0441\u0443\u0442\u043d\u0456: \u043f\u0456\u0434\u0442\u0432\u0435\u0440\u0434\u0436\u0435\u043d\u0438\u0439 \u043a\u043b\u044e\u0447 \u043f\u0456\u0434\u043f\u0438\u0441\u0443\u0432\u0430\u0447\u0430]" file="tools/test_verification_launcher.py" line="63" time="0.645" /><testcase classname="tools.test_verification_launcher" name="test_failure_is_nonzero_and_written_to_transcript[wrong_key]" file="tools/test_verification_launcher.py" line="81" time="0.469" /><testcase classname="tools.test_verification_launcher" name="test_failure_is_nonzero_and_written_to_transcript[altered_file]" file="tools/test_verification_launcher.py" line="81" time="0.509" /><testcase classname="tools.test_verification_launcher" name="test_key_entry_accepts_grouped_hex_but_never_executes_text" file="tools/test_verification_launcher.py" line="98" time="0.457" /><testcase classname="tools.test_verification_launcher" name="test_interactive_keeps_assurance_requirements[options0]" file="tools/test_verification_launcher.py" line="108" time="0.506" /><testcase classname="tools.test_verification_launcher" name="test_interactive_keeps_assurance_requirements[options1]" file="tools/test_verification_launcher.py" line="108" time="0.603" /><testcase classname="tools.test_verification_launcher" name="test_interactive_rejects_unpaired_attestation_inputs" file="tools/test_verification_launcher.py" line="117" time="0.650" /><testcase classname="tools.test_verification_launcher" name="test_interactive_transcript_sanitizes_archive_path" file="tools/test_verification_launcher.py" line="124" time="0.567" /><testcase classname="tools.test_verification_launcher" name="test_missing_runtime_does_not_claim_html_is_archive_verification" file="tools/test_verification_launcher.py" line="136" time="0.001"><skipped type="pytest.skip" message="Windows launcher">/workspace/qa/src/db86ca0b4e82515795ccc1c5e32a55579582c0fe/tools/test_verification_launcher.py:139: Windows launcher</skipped></testcase><testcase classname="tools.test_verification_launcher" name="test_actual_cmd_preserves_paths_failure_codes_and_ignores_adjacent_modules" file="tools/test_verification_launcher.py" line="148" time="0.326"><skipped type="pytest.skip" message="Windows launcher">/workspace/qa/src/db86ca0b4e82515795ccc1c5e32a55579582c0fe/tools/test_verification_launcher.py:151: Windows launcher</skipped></testcase><testcase classname="tools.test_verification_launcher" name="test_cancel_and_html_never_produce_success" file="tools/test_verification_launcher.py" line="166" time="0.913" /><testcase classname="tools.test_verification_launcher" name="test_chat_and_handover_export_the_same_kit_with_report_language" file="tools/test_verification_launcher.py" line="176" time="3.019" /><testcase classname="tools.test_verification_launcher" name="test_no_automatic_choice_between_multiple_archives" file="tools/test_verification_launcher.py" line="197" time="0.513" /><testcase classname="tools.test_verification_launcher" name="test_explain_does_not_change_machine_json" file="tools/test_verification_launcher.py" line="208" time="0.578" /><testcase classname="tools.test_verification_launcher" name="test_witness_export_signs_launchers_without_claiming_collector_coverage" file="tools/test_verification_launcher.py" line="217" time="1.184" /><testcase classname="tools.test_verifier_account_compatibility" name="test_new_account_and_disclosure_match_old_verifier[None]" file="tools/test_verifier_account_compatibility.py" line="134" time="3.803" /><testcase classname="tools.test_verifier_account_compatibility" name="test_new_account_and_disclosure_match_old_verifier[valid]" file="tools/test_verifier_account_compatibility.py" line="134" time="1.309" /><testcase classname="tools.test_verifier_account_compatibility" name="test_new_account_and_disclosure_match_old_verifier[0000000000000000000000000000000000000000000000000000000000000000]" file="tools/test_verifier_account_compatibility.py" line="134" time="0.015" /><testcase classname="tools.test_verifier_account_compatibility" name="test_signed_account_rejections_match_old_verifier[duplicate_task-Duplicate or invalid account export task ID]" file="tools/test_verifier_account_compatibility.py" line="146" time="0.020" /><testcase classname="tools.test_verifier_account_compatibility" name="test_signed_account_rejections_match_old_verifier[unselected_chat-outside the selected inventory]" file="tools/test_verifier_account_compatibility.py" line="146" time="0.011" /><testcase classname="tools.test_verifier_account_compatibility" name="test_signed_account_rejections_match_old_verifier[initial_cursor-Invalid message task boundary]" file="tools/test_verifier_account_compatibility.py" line="146" time="0.011" /><testcase classname="tools.test_verifier_account_compatibility" name="test_signed_account_rejections_match_old_verifier[terminal_type-task cursor continuity]" file="tools/test_verifier_account_compatibility.py" line="146" time="0.131" /><testcase classname="tools.test_verifier_account_compatibility" name="test_signed_account_rejections_match_old_verifier[page_chat_type-receipt task scope mismatch]" file="tools/test_verifier_account_compatibility.py" line="146" time="0.120" /><testcase classname="tools.test_verifier_account_compatibility" name="test_signed_account_rejections_match_old_verifier[page_count-page record count mismatch]" file="tools/test_verifier_account_compatibility.py" line="146" time="0.126" /><testcase classname="tools.test_verifier_account_compatibility" name="test_signed_account_rejections_match_old_verifier[record_order-outside the signed pagination boundary]" file="tools/test_verifier_account_compatibility.py" line="146" time="0.121" /><testcase classname="tools.test_verifier_account_compatibility" name="test_signed_account_rejections_match_old_verifier[message_time-explicit UTC offset]" file="tools/test_verifier_account_compatibility.py" line="146" time="0.116" /><testcase classname="tools.test_verifier_account_compatibility" name="test_signed_account_rejections_match_old_verifier[own_only-own-message scope mismatch]" file="tools/test_verifier_account_compatibility.py" line="146" time="0.118" /><testcase classname="tools.test_verifier_account_compatibility" name="test_signed_account_rejections_match_old_verifier[sender_filter-sender selection mismatch]" file="tools/test_verifier_account_compatibility.py" line="146" time="0.263" /><testcase classname="tools.test_verifier_account_compatibility" name="test_signed_account_rejections_match_old_verifier[text_filter-text selection mismatch]" file="tools/test_verifier_account_compatibility.py" line="146" time="0.254" /><testcase classname="tools.test_verifier_account_compatibility" name="test_signed_account_rejections_match_old_verifier[date_filter-outside the selected date range]" file="tools/test_verifier_account_compatibility.py" line="146" time="0.158" /><testcase classname="tools.test_verifier_account_compatibility" name="test_signed_account_rejections_match_old_verifier[attachment_saved_claim-Unsaved account export attachment claims saved bytes]" file="tools/test_verifier_account_compatibility.py" line="146" time="0.180" /><testcase classname="tools.test_verifier_account_compatibility" name="test_signed_account_rejections_match_old_verifier[attachment_outcome-Invalid account export attachment outcome]" file="tools/test_verifier_account_compatibility.py" line="146" time="0.311" /><testcase classname="tools.test_verifier_account_compatibility" name="test_signed_account_rejections_match_old_verifier[false_completeness-completeness claim disagrees]" file="tools/test_verifier_account_compatibility.py" line="146" time="0.185" /><testcase classname="tools.test_verifier_account_compatibility" name="test_signed_account_rejections_match_old_verifier[manifest_count-manifest counts mismatch]" file="tools/test_verifier_account_compatibility.py" line="146" time="0.301" /><testcase classname="tools.test_verifier_account_compatibility" name="test_signed_account_rejections_match_old_verifier[hash_only_count-hash-only attachment count mismatch]" file="tools/test_verifier_account_compatibility.py" line="146" time="0.251" /><testcase classname="tools.test_verifier_account_compatibility" name="test_signed_account_rejections_match_old_verifier[noncanonical-must be canonical JSONL]" file="tools/test_verifier_account_compatibility.py" line="146" time="0.206" /><testcase classname="tools.test_verifier_account_compatibility" name="test_partial_account_results_remain_partial[unfinished]" file="tools/test_verifier_account_compatibility.py" line="210" time="0.480" /><testcase classname="tools.test_verifier_account_compatibility" name="test_partial_account_results_remain_partial[failed_page]" file="tools/test_verifier_account_compatibility.py" line="210" time="0.351" /><testcase classname="tools.test_verifier_account_compatibility" name="test_partial_account_results_remain_partial[failed_attachment]" file="tools/test_verifier_account_compatibility.py" line="210" time="0.210" /><testcase classname="tools.test_verifier_account_compatibility" name="test_partial_account_results_remain_partial[discovery_gap]" file="tools/test_verifier_account_compatibility.py" line="210" time="0.132" /><testcase classname="tools.test_verifier_account_compatibility" name="test_signed_disclosure_rejections_match_old_verifier[duplicate-Duplicate disclosure message]" file="tools/test_verifier_account_compatibility.py" line="232" time="0.292" /><testcase classname="tools.test_verifier_account_compatibility" name="test_signed_disclosure_rejections_match_old_verifier[envelope-Invalid disclosure message envelope]" file="tools/test_verifier_account_compatibility.py" line="232" time="0.307" /><testcase classname="tools.test_verifier_account_compatibility" name="test_signed_disclosure_rejections_match_old_verifier[id_type-Invalid disclosure chat/message ID]" file="tools/test_verifier_account_compatibility.py" line="232" time="0.321" /><testcase classname="tools.test_verifier_account_compatibility" name="test_signed_disclosure_rejections_match_old_verifier[state-Invalid disclosure record state]" file="tools/test_verifier_account_compatibility.py" line="232" time="0.320" /><testcase classname="tools.test_verifier_account_compatibility" name="test_signed_disclosure_rejections_match_old_verifier[marker_payload-Invalid withheld-by-selection marker]" file="tools/test_verifier_account_compatibility.py" line="232" time="0.274" /><testcase classname="tools.test_verifier_account_compatibility" name="test_signed_disclosure_rejections_match_old_verifier[marker_count-Invalid withheld-by-selection marker]" file="tools/test_verifier_account_compatibility.py" line="232" time="0.274" /><testcase classname="tools.test_verifier_account_compatibility" name="test_signed_disclosure_rejections_match_old_verifier[reply-points at a record]" file="tools/test_verifier_account_compatibility.py" line="232" time="0.269" /><testcase classname="tools.test_verifier_account_compatibility" name="test_signed_disclosure_rejections_match_old_verifier[attachment-Unsaved disclosure attachment claims saved bytes]" file="tools/test_verifier_account_compatibility.py" line="232" time="0.310" /><testcase classname="tools.test_verifier_account_compatibility" name="test_signed_disclosure_rejections_match_old_verifier[count-Disclosure manifest counts mismatch]" file="tools/test_verifier_account_compatibility.py" line="232" time="0.348" /><testcase classname="tools.test_verifier_account_compatibility" name="test_signed_disclosure_rejections_match_old_verifier[source_reference-Invalid disclosure source reference]" file="tools/test_verifier_account_compatibility.py" line="232" time="0.017" /><testcase classname="tools.test_verifier_comparison" name="test_comparison_uses_text_beyond_the_display_excerpt[False]" file="tools/test_verifier_comparison.py" line="28" time="3.584" /><testcase classname="tools.test_verifier_comparison" name="test_comparison_uses_text_beyond_the_display_excerpt[True]" file="tools/test_verifier_comparison.py" line="28" time="2.354" /><testcase classname="tools.test_verifier_comparison" name="test_heuristic_pairs_still_compare_full_content" file="tools/test_verifier_comparison.py" line="43" time="2.466" /><testcase classname="tools.test_verifier_comparison" name="test_comparison_checks_every_recorded_metadata_field[reply_to_message_id-10-20]" file="tools/test_verifier_comparison.py" line="51" time="1.294" /><testcase classname="tools.test_verifier_comparison" name="test_comparison_checks_every_recorded_metadata_field[from_id-1001-1002]" file="tools/test_verifier_comparison.py" line="51" time="1.247" /><testcase classname="tools.test_verifier_comparison" name="test_comparison_checks_every_recorded_metadata_field[date-2026-11-05T00:00:00+00:00-2026-11-05T10:00:00+00:00]" file="tools/test_verifier_comparison.py" line="51" time="2.453" /><testcase classname="tools.test_verifier_comparison" name="test_comparison_checks_every_recorded_metadata_field[date_unixtime-1793836800-1793872800]" file="tools/test_verifier_comparison.py" line="51" time="1.256" /><testcase classname="tools.test_verifier_comparison" name="test_comparison_checks_every_recorded_metadata_field[forwarded_from-Original source-Other source]" file="tools/test_verifier_comparison.py" line="51" time="1.641" /><testcase classname="tools.test_verifier_comparison" name="test_comparison_checks_every_recorded_metadata_field[reactions-first5-second5]" file="tools/test_verifier_comparison.py" line="51" time="2.634" /><testcase classname="tools.test_verifier_comparison" name="test_comparison_checks_every_recorded_metadata_field[entities-first6-second6]" file="tools/test_verifier_comparison.py" line="51" time="1.260" /><testcase classname="tools.test_verifier_comparison" name="test_comparison_checks_every_recorded_metadata_field[future_metadata-first7-second7]" file="tools/test_verifier_comparison.py" line="51" time="1.227" /><testcase classname="tools.test_verifier_comparison" name="test_equal_records_ignore_object_key_order_but_distinguish_missing_fields" file="tools/test_verifier_comparison.py" line="69" time="3.589" /><testcase classname="tools.test_verifier_comparison" name="test_comparison_rejects_checks_it_cannot_perform[options0]" file="tools/test_verifier_comparison.py" line="78" time="1.171" /><testcase classname="tools.test_verifier_comparison" name="test_comparison_rejects_checks_it_cannot_perform[options1]" file="tools/test_verifier_comparison.py" line="78" time="1.147" /><testcase classname="tools.test_verifier_comparison" name="test_comparison_rejects_checks_it_cannot_perform[options2]" file="tools/test_verifier_comparison.py" line="78" time="2.403" /><testcase classname="tools.test_verifier_comparison" name="test_comparison_rejects_checks_it_cannot_perform[options3]" file="tools/test_verifier_comparison.py" line="78" time="1.141" /><testcase classname="tools.test_verifier_comparison" name="test_comparison_rejects_checks_it_cannot_perform[options4]" file="tools/test_verifier_comparison.py" line="78" time="1.139" /><testcase classname="tools.test_verifier_comparison" name="test_comparison_rejects_checks_it_cannot_perform[options5]" file="tools/test_verifier_comparison.py" line="78" time="2.364" /><testcase classname="tools.test_verifier_comparison" name="test_comparison_rejects_checks_it_cannot_perform[options6]" file="tools/test_verifier_comparison.py" line="78" time="1.151" /><testcase classname="tools.test_verifier_comparison" name="test_comparison_rejects_checks_it_cannot_perform[options7]" file="tools/test_verifier_comparison.py" line="78" time="1.142" /><testcase classname="tools.test_verifier_comparison" name="test_ots_structure_only_does_not_get_a_positive_indicator[pending]" file="tools/test_verifier_comparison.py" line="96" time="0.000" /><testcase classname="tools.test_verifier_comparison" name="test_ots_structure_only_does_not_get_a_positive_indicator[bitcoin-unverified]" file="tools/test_verifier_comparison.py" line="96" time="0.000" /><testcase classname="tools.test_verifier_comparison" name="test_ots_structure_only_does_not_get_a_positive_indicator[unknown]" file="tools/test_verifier_comparison.py" line="96" time="0.000"><failure message="AssertionError: assert 'unknown' in 'synthetic'">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':
&gt;           assert 'unknown' in checks[0][2]
E           AssertionError: assert 'unknown' in 'synthetic'

tools/test_verifier_comparison.py:106: AssertionError</failure></testcase><testcase classname="tools.test_verifier_dispatch" name="test_direct_check_preserves_policy_and_archive_without_printing[tgwitness.verify]" file="tools/test_verifier_dispatch.py" line="14" time="0.005"><failure message="AssertionError: assert False&#10;[+2 more lines; full report in element text]">module = 'tgwitness.verify'
capsys = &lt;_pytest.capture.CaptureFixture object at 0x747f417dffb0&gt;

    @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
&gt;       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}, ...}, ...} = &lt;tgwitness.verify.CheckResult object at 0x747f36d1b380&gt;.details

tools/test_verifier_dispatch.py:24: AssertionError</failure></testcase><testcase classname="tools.test_verifier_dispatch" name="test_direct_check_preserves_policy_and_archive_without_printing[tgwitness.verifier.cli]" file="tools/test_verifier_dispatch.py" line="14" time="0.018"><failure message="AssertionError: assert False&#10;[+2 more lines; full report in element text]">module = 'tgwitness.verifier.cli'
capsys = &lt;_pytest.capture.CaptureFixture object at 0x747f417df8c0&gt;

    @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
&gt;       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}, ...}, ...} = &lt;tgwitness.verifier.cli.CheckResult object at 0x747f37d745c0&gt;.details

tools/test_verifier_dispatch.py:24: AssertionError</failure></testcase><testcase classname="tools.test_verifier_dispatch" name="test_future_json_format_is_authenticated_before_unsupported_status[False]" file="tools/test_verifier_dispatch.py" line="29" time="0.001" /><testcase classname="tools.test_verifier_dispatch" name="test_future_json_format_is_authenticated_before_unsupported_status[True]" file="tools/test_verifier_dispatch.py" line="29" time="0.001" /><testcase classname="tools.test_verifier_dispatch" name="test_inapplicable_archive_checks_are_rejected_before_dispatch[tgwitness-account-export-v1-checkpoint]" file="tools/test_verifier_dispatch.py" line="41" time="0.001" /><testcase classname="tools.test_verifier_dispatch" name="test_inapplicable_archive_checks_are_rejected_before_dispatch[tgwitness-account-export-v1-witness]" file="tools/test_verifier_dispatch.py" line="41" time="0.001" /><testcase classname="tools.test_verifier_dispatch" name="test_inapplicable_archive_checks_are_rejected_before_dispatch[tgwitness-account-export-v1-tsa_ca]" file="tools/test_verifier_dispatch.py" line="41" time="0.001" /><testcase classname="tools.test_verifier_dispatch" name="test_inapplicable_archive_checks_are_rejected_before_dispatch[tgwitness-account-export-v1-channel]" file="tools/test_verifier_dispatch.py" line="41" time="0.001" /><testcase classname="tools.test_verifier_dispatch" name="test_inapplicable_archive_checks_are_rejected_before_dispatch[tgwitness-account-export-v1-evidence]" file="tools/test_verifier_dispatch.py" line="41" time="0.001" /><testcase classname="tools.test_verifier_dispatch" name="test_inapplicable_archive_checks_are_rejected_before_dispatch[tgwitness-account-disclosure-v1-checkpoint]" file="tools/test_verifier_dispatch.py" line="41" time="0.001" /><testcase classname="tools.test_verifier_dispatch" name="test_inapplicable_archive_checks_are_rejected_before_dispatch[tgwitness-account-disclosure-v1-witness]" file="tools/test_verifier_dispatch.py" line="41" time="0.001" /><testcase classname="tools.test_verifier_dispatch" name="test_inapplicable_archive_checks_are_rejected_before_dispatch[tgwitness-account-disclosure-v1-tsa_ca]" file="tools/test_verifier_dispatch.py" line="41" time="0.001" /><testcase classname="tools.test_verifier_dispatch" name="test_inapplicable_archive_checks_are_rejected_before_dispatch[tgwitness-account-disclosure-v1-channel]" file="tools/test_verifier_dispatch.py" line="41" time="0.001" /><testcase classname="tools.test_verifier_dispatch" name="test_inapplicable_archive_checks_are_rejected_before_dispatch[tgwitness-account-disclosure-v2-checkpoint]" file="tools/test_verifier_dispatch.py" line="41" time="0.001" /><testcase classname="tools.test_verifier_dispatch" name="test_inapplicable_archive_checks_are_rejected_before_dispatch[tgwitness-account-disclosure-v2-witness]" file="tools/test_verifier_dispatch.py" line="41" time="0.001" /><testcase classname="tools.test_verifier_dispatch" name="test_inapplicable_archive_checks_are_rejected_before_dispatch[tgwitness-account-disclosure-v2-tsa_ca]" file="tools/test_verifier_dispatch.py" line="41" time="0.001" /><testcase classname="tools.test_verifier_dispatch" name="test_inapplicable_archive_checks_are_rejected_before_dispatch[tgwitness-account-disclosure-v2-channel]" file="tools/test_verifier_dispatch.py" line="41" time="0.001" /><testcase classname="tools.test_verifier_dispatch" name="test_distributed_directory_rejects_journal_options[checkpoint]" file="tools/test_verifier_dispatch.py" line="60" time="0.001" /><testcase classname="tools.test_verifier_dispatch" name="test_distributed_directory_rejects_journal_options[witness]" file="tools/test_verifier_dispatch.py" line="60" time="0.001" /><testcase classname="tools.test_verifier_dispatch" name="test_distributed_directory_rejects_journal_options[tsa_ca]" file="tools/test_verifier_dispatch.py" line="60" time="0.001" /><testcase classname="tools.test_verifier_dispatch" name="test_distributed_directory_rejects_journal_options[channel]" file="tools/test_verifier_dispatch.py" line="60" time="0.001" /><testcase classname="tools.test_verifier_dispatch" name="test_distributed_directory_rejects_journal_options[evidence]" file="tools/test_verifier_dispatch.py" line="60" time="0.001" /><testcase classname="tools.test_verifier_languages" name="test_builder_starts_without_host_application_dependencies" file="tools/test_verifier_languages.py" line="19" time="0.057" /><testcase classname="tools.test_verifier_languages" name="test_catalogue_matches_panel_and_standalone_copy" file="tools/test_verifier_languages.py" line="26" time="0.052" /><testcase classname="tools.test_verifier_languages" name="test_all_languages_cover_real_results_and_failures[unconfirmed-en]" file="tools/test_verifier_languages.py" line="41" time="0.147" /><testcase classname="tools.test_verifier_languages" name="test_all_languages_cover_real_results_and_failures[unconfirmed-uk]" file="tools/test_verifier_languages.py" line="41" time="0.140" /><testcase classname="tools.test_verifier_languages" name="test_all_languages_cover_real_results_and_failures[unconfirmed-es]" file="tools/test_verifier_languages.py" line="41" time="0.141" /><testcase classname="tools.test_verifier_languages" name="test_all_languages_cover_real_results_and_failures[unconfirmed-pt]" file="tools/test_verifier_languages.py" line="41" time="0.149" /><testcase classname="tools.test_verifier_languages" name="test_all_languages_cover_real_results_and_failures[unconfirmed-tr]" file="tools/test_verifier_languages.py" line="41" time="0.144" /><testcase classname="tools.test_verifier_languages" name="test_all_languages_cover_real_results_and_failures[unconfirmed-ar]" file="tools/test_verifier_languages.py" line="41" time="0.143" /><testcase classname="tools.test_verifier_languages" name="test_all_languages_cover_real_results_and_failures[unconfirmed-fa]" file="tools/test_verifier_languages.py" line="41" time="0.140" /><testcase classname="tools.test_verifier_languages" name="test_all_languages_cover_real_results_and_failures[unconfirmed-ur]" file="tools/test_verifier_languages.py" line="41" time="0.152" /><testcase classname="tools.test_verifier_languages" name="test_all_languages_cover_real_results_and_failures[unconfirmed-hi]" file="tools/test_verifier_languages.py" line="41" time="0.143" /><testcase classname="tools.test_verifier_languages" name="test_all_languages_cover_real_results_and_failures[unconfirmed-id]" file="tools/test_verifier_languages.py" line="41" time="0.142" /><testcase classname="tools.test_verifier_languages" name="test_all_languages_cover_real_results_and_failures[unconfirmed-vi]" file="tools/test_verifier_languages.py" line="41" time="0.142" /><testcase classname="tools.test_verifier_languages" name="test_all_languages_cover_real_results_and_failures[unconfirmed-zh]" file="tools/test_verifier_languages.py" line="41" time="0.141" /><testcase classname="tools.test_verifier_languages" name="test_all_languages_cover_real_results_and_failures[unconfirmed-fr]" file="tools/test_verifier_languages.py" line="41" time="0.141" /><testcase classname="tools.test_verifier_languages" name="test_all_languages_cover_real_results_and_failures[unconfirmed-de]" file="tools/test_verifier_languages.py" line="41" time="0.146" /><testcase classname="tools.test_verifier_languages" name="test_all_languages_cover_real_results_and_failures[unconfirmed-it]" file="tools/test_verifier_languages.py" line="41" time="0.143" /><testcase classname="tools.test_verifier_languages" name="test_all_languages_cover_real_results_and_failures[unconfirmed-uz]" file="tools/test_verifier_languages.py" line="41" time="0.140" /><testcase classname="tools.test_verifier_languages" name="test_all_languages_cover_real_results_and_failures[unconfirmed-ko]" file="tools/test_verifier_languages.py" line="41" time="0.145" /><testcase classname="tools.test_verifier_languages" name="test_all_languages_cover_real_results_and_failures[unconfirmed-zh-Hant]" file="tools/test_verifier_languages.py" line="41" time="0.142" /><testcase classname="tools.test_verifier_languages" name="test_all_languages_cover_real_results_and_failures[unconfirmed-ms]" file="tools/test_verifier_languages.py" line="41" time="0.142" /><testcase classname="tools.test_verifier_languages" name="test_all_languages_cover_real_results_and_failures[unconfirmed-pl]" file="tools/test_verifier_languages.py" line="41" time="0.145" /><testcase classname="tools.test_verifier_languages" name="test_all_languages_cover_real_results_and_failures[unconfirmed-ja]" file="tools/test_verifier_languages.py" line="41" time="0.139" /><testcase classname="tools.test_verifier_languages" name="test_all_languages_cover_real_results_and_failures[unconfirmed-th]" file="tools/test_verifier_languages.py" line="41" time="0.141" /><testcase classname="tools.test_verifier_languages" name="test_all_languages_cover_real_results_and_failures[unconfirmed-he]" file="tools/test_verifier_languages.py" line="41" time="0.145" /><testcase classname="tools.test_verifier_languages" name="test_all_languages_cover_real_results_and_failures[unconfirmed-bn]" file="tools/test_verifier_languages.py" line="41" time="0.143" /><testcase classname="tools.test_verifier_languages" name="test_all_languages_cover_real_results_and_failures[unconfirmed-ru]" file="tools/test_verifier_languages.py" line="41" time="0.142" /><testcase classname="tools.test_verifier_languages" name="test_all_languages_cover_real_results_and_failures[wrong_key-en]" file="tools/test_verifier_languages.py" line="41" time="0.138" /><testcase classname="tools.test_verifier_languages" name="test_all_languages_cover_real_results_and_failures[wrong_key-uk]" file="tools/test_verifier_languages.py" line="41" time="0.142" /><testcase classname="tools.test_verifier_languages" name="test_all_languages_cover_real_results_and_failures[wrong_key-es]" file="tools/test_verifier_languages.py" line="41" time="0.136" /><testcase classname="tools.test_verifier_languages" name="test_all_languages_cover_real_results_and_failures[wrong_key-pt]" file="tools/test_verifier_languages.py" line="41" time="0.134" /><testcase classname="tools.test_verifier_languages" name="test_all_languages_cover_real_results_and_failures[wrong_key-tr]" file="tools/test_verifier_languages.py" line="41" time="0.138" /><testcase classname="tools.test_verifier_languages" name="test_all_languages_cover_real_results_and_failures[wrong_key-ar]" file="tools/test_verifier_languages.py" line="41" time="0.140" /><testcase classname="tools.test_verifier_languages" name="test_all_languages_cover_real_results_and_failures[wrong_key-fa]" file="tools/test_verifier_languages.py" line="41" time="0.136" /><testcase classname="tools.test_verifier_languages" name="test_all_languages_cover_real_results_and_failures[wrong_key-ur]" file="tools/test_verifier_languages.py" line="41" time="0.137" /><testcase classname="tools.test_verifier_languages" name="test_all_languages_cover_real_results_and_failures[wrong_key-hi]" file="tools/test_verifier_languages.py" line="41" time="0.139" /><testcase classname="tools.test_verifier_languages" name="test_all_languages_cover_real_results_and_failures[wrong_key-id]" file="tools/test_verifier_languages.py" line="41" time="0.144" /><testcase classname="tools.test_verifier_languages" name="test_all_languages_cover_real_results_and_failures[wrong_key-vi]" file="tools/test_verifier_languages.py" line="41" time="0.137" /><testcase classname="tools.test_verifier_languages" name="test_all_languages_cover_real_results_and_failures[wrong_key-zh]" file="tools/test_verifier_languages.py" line="41" time="0.134" /><testcase classname="tools.test_verifier_languages" name="test_all_languages_cover_real_results_and_failures[wrong_key-fr]" file="tools/test_verifier_languages.py" line="41" time="0.138" /><testcase classname="tools.test_verifier_languages" name="test_all_languages_cover_real_results_and_failures[wrong_key-de]" file="tools/test_verifier_languages.py" line="41" time="0.136" /><testcase classname="tools.test_verifier_languages" name="test_all_languages_cover_real_results_and_failures[wrong_key-it]" file="tools/test_verifier_languages.py" line="41" time="0.135" /><testcase classname="tools.test_verifier_languages" name="test_all_languages_cover_real_results_and_failures[wrong_key-uz]" file="tools/test_verifier_languages.py" line="41" time="0.138" /><testcase classname="tools.test_verifier_languages" name="test_all_languages_cover_real_results_and_failures[wrong_key-ko]" file="tools/test_verifier_languages.py" line="41" time="0.136" /><testcase classname="tools.test_verifier_languages" name="test_all_languages_cover_real_results_and_failures[wrong_key-zh-Hant]" file="tools/test_verifier_languages.py" line="41" time="0.138" /><testcase classname="tools.test_verifier_languages" name="test_all_languages_cover_real_results_and_failures[wrong_key-ms]" file="tools/test_verifier_languages.py" line="41" time="0.139" /><testcase classname="tools.test_verifier_languages" name="test_all_languages_cover_real_results_and_failures[wrong_key-pl]" file="tools/test_verifier_languages.py" line="41" time="0.141" /><testcase classname="tools.test_verifier_languages" name="test_all_languages_cover_real_results_and_failures[wrong_key-ja]" file="tools/test_verifier_languages.py" line="41" time="0.137" /><testcase classname="tools.test_verifier_languages" name="test_all_languages_cover_real_results_and_failures[wrong_key-th]" file="tools/test_verifier_languages.py" line="41" time="0.135" /><testcase classname="tools.test_verifier_languages" name="test_all_languages_cover_real_results_and_failures[wrong_key-he]" file="tools/test_verifier_languages.py" line="41" time="0.136" /><testcase classname="tools.test_verifier_languages" name="test_all_languages_cover_real_results_and_failures[wrong_key-bn]" file="tools/test_verifier_languages.py" line="41" time="0.136" /><testcase classname="tools.test_verifier_languages" name="test_all_languages_cover_real_results_and_failures[wrong_key-ru]" file="tools/test_verifier_languages.py" line="41" time="0.137" /><testcase classname="tools.test_verifier_languages" name="test_all_languages_cover_real_results_and_failures[cancelled-en]" file="tools/test_verifier_languages.py" line="41" time="0.133" /><testcase classname="tools.test_verifier_languages" name="test_all_languages_cover_real_results_and_failures[cancelled-uk]" file="tools/test_verifier_languages.py" line="41" time="0.142" /><testcase classname="tools.test_verifier_languages" name="test_all_languages_cover_real_results_and_failures[cancelled-es]" file="tools/test_verifier_languages.py" line="41" time="0.132" /><testcase classname="tools.test_verifier_languages" name="test_all_languages_cover_real_results_and_failures[cancelled-pt]" file="tools/test_verifier_languages.py" line="41" time="0.131" /><testcase classname="tools.test_verifier_languages" name="test_all_languages_cover_real_results_and_failures[cancelled-tr]" file="tools/test_verifier_languages.py" line="41" time="0.131" /><testcase classname="tools.test_verifier_languages" name="test_all_languages_cover_real_results_and_failures[cancelled-ar]" file="tools/test_verifier_languages.py" line="41" time="0.131" /><testcase classname="tools.test_verifier_languages" name="test_all_languages_cover_real_results_and_failures[cancelled-fa]" file="tools/test_verifier_languages.py" line="41" time="0.131" /><testcase classname="tools.test_verifier_languages" name="test_all_languages_cover_real_results_and_failures[cancelled-ur]" file="tools/test_verifier_languages.py" line="41" time="0.132" /><testcase classname="tools.test_verifier_languages" name="test_all_languages_cover_real_results_and_failures[cancelled-hi]" file="tools/test_verifier_languages.py" line="41" time="0.137" /><testcase classname="tools.test_verifier_languages" name="test_all_languages_cover_real_results_and_failures[cancelled-id]" file="tools/test_verifier_languages.py" line="41" time="0.133" /><testcase classname="tools.test_verifier_languages" name="test_all_languages_cover_real_results_and_failures[cancelled-vi]" file="tools/test_verifier_languages.py" line="41" time="0.133" /><testcase classname="tools.test_verifier_languages" name="test_all_languages_cover_real_results_and_failures[cancelled-zh]" file="tools/test_verifier_languages.py" line="41" time="0.134" /><testcase classname="tools.test_verifier_languages" name="test_all_languages_cover_real_results_and_failures[cancelled-fr]" file="tools/test_verifier_languages.py" line="41" time="0.133" /><testcase classname="tools.test_verifier_languages" name="test_all_languages_cover_real_results_and_failures[cancelled-de]" file="tools/test_verifier_languages.py" line="41" time="0.133" /><testcase classname="tools.test_verifier_languages" name="test_all_languages_cover_real_results_and_failures[cancelled-it]" file="tools/test_verifier_languages.py" line="41" time="0.131" /><testcase classname="tools.test_verifier_languages" name="test_all_languages_cover_real_results_and_failures[cancelled-uz]" file="tools/test_verifier_languages.py" line="41" time="0.138" /><testcase classname="tools.test_verifier_languages" name="test_all_languages_cover_real_results_and_failures[cancelled-ko]" file="tools/test_verifier_languages.py" line="41" time="0.129" /><testcase classname="tools.test_verifier_languages" name="test_all_languages_cover_real_results_and_failures[cancelled-zh-Hant]" file="tools/test_verifier_languages.py" line="41" time="0.130" /><testcase classname="tools.test_verifier_languages" name="test_all_languages_cover_real_results_and_failures[cancelled-ms]" file="tools/test_verifier_languages.py" line="41" time="0.132" /><testcase classname="tools.test_verifier_languages" name="test_all_languages_cover_real_results_and_failures[cancelled-pl]" file="tools/test_verifier_languages.py" line="41" time="0.132" /><testcase classname="tools.test_verifier_languages" name="test_all_languages_cover_real_results_and_failures[cancelled-ja]" file="tools/test_verifier_languages.py" line="41" time="0.131" /><testcase classname="tools.test_verifier_languages" name="test_all_languages_cover_real_results_and_failures[cancelled-th]" file="tools/test_verifier_languages.py" line="41" time="0.130" /><testcase classname="tools.test_verifier_languages" name="test_all_languages_cover_real_results_and_failures[cancelled-he]" file="tools/test_verifier_languages.py" line="41" time="0.135" /><testcase classname="tools.test_verifier_languages" name="test_all_languages_cover_real_results_and_failures[cancelled-bn]" file="tools/test_verifier_languages.py" line="41" time="0.130" /><testcase classname="tools.test_verifier_languages" name="test_all_languages_cover_real_results_and_failures[cancelled-ru]" file="tools/test_verifier_languages.py" line="41" time="0.132" /><testcase classname="tools.test_verifier_languages" name="test_windows_missing_runtime_is_localized_before_python_starts[en]" file="tools/test_verifier_languages.py" line="79" time="0.001"><skipped type="pytest.skip" message="Windows bootstrap">/workspace/qa/src/db86ca0b4e82515795ccc1c5e32a55579582c0fe/tools/test_verifier_languages.py:83: Windows bootstrap</skipped></testcase><testcase classname="tools.test_verifier_languages" name="test_windows_missing_runtime_is_localized_before_python_starts[uk]" file="tools/test_verifier_languages.py" line="79" time="0.001"><skipped type="pytest.skip" message="Windows bootstrap">/workspace/qa/src/db86ca0b4e82515795ccc1c5e32a55579582c0fe/tools/test_verifier_languages.py:83: Windows bootstrap</skipped></testcase><testcase classname="tools.test_verifier_languages" name="test_windows_missing_runtime_is_localized_before_python_starts[es]" file="tools/test_verifier_languages.py" line="79" time="0.000"><skipped type="pytest.skip" message="Windows bootstrap">/workspace/qa/src/db86ca0b4e82515795ccc1c5e32a55579582c0fe/tools/test_verifier_languages.py:83: Windows bootstrap</skipped></testcase><testcase classname="tools.test_verifier_languages" name="test_windows_missing_runtime_is_localized_before_python_starts[pt]" file="tools/test_verifier_languages.py" line="79" time="0.000"><skipped type="pytest.skip" message="Windows bootstrap">/workspace/qa/src/db86ca0b4e82515795ccc1c5e32a55579582c0fe/tools/test_verifier_languages.py:83: Windows bootstrap</skipped></testcase><testcase classname="tools.test_verifier_languages" name="test_windows_missing_runtime_is_localized_before_python_starts[tr]" file="tools/test_verifier_languages.py" line="79" time="0.000"><skipped type="pytest.skip" message="Windows bootstrap">/workspace/qa/src/db86ca0b4e82515795ccc1c5e32a55579582c0fe/tools/test_verifier_languages.py:83: Windows bootstrap</skipped></testcase><testcase classname="tools.test_verifier_languages" name="test_windows_missing_runtime_is_localized_before_python_starts[ar]" file="tools/test_verifier_languages.py" line="79" time="0.000"><skipped type="pytest.skip" message="Windows bootstrap">/workspace/qa/src/db86ca0b4e82515795ccc1c5e32a55579582c0fe/tools/test_verifier_languages.py:83: Windows bootstrap</skipped></testcase><testcase classname="tools.test_verifier_languages" name="test_windows_missing_runtime_is_localized_before_python_starts[fa]" file="tools/test_verifier_languages.py" line="79" time="0.000"><skipped type="pytest.skip" message="Windows bootstrap">/workspace/qa/src/db86ca0b4e82515795ccc1c5e32a55579582c0fe/tools/test_verifier_languages.py:83: Windows bootstrap</skipped></testcase><testcase classname="tools.test_verifier_languages" name="test_windows_missing_runtime_is_localized_before_python_starts[ur]" file="tools/test_verifier_languages.py" line="79" time="0.000"><skipped type="pytest.skip" message="Windows bootstrap">/workspace/qa/src/db86ca0b4e82515795ccc1c5e32a55579582c0fe/tools/test_verifier_languages.py:83: Windows bootstrap</skipped></testcase><testcase classname="tools.test_verifier_languages" name="test_windows_missing_runtime_is_localized_before_python_starts[hi]" file="tools/test_verifier_languages.py" line="79" time="0.000"><skipped type="pytest.skip" message="Windows bootstrap">/workspace/qa/src/db86ca0b4e82515795ccc1c5e32a55579582c0fe/tools/test_verifier_languages.py:83: Windows bootstrap</skipped></testcase><testcase classname="tools.test_verifier_languages" name="test_windows_missing_runtime_is_localized_before_python_starts[id]" file="tools/test_verifier_languages.py" line="79" time="0.000"><skipped type="pytest.skip" message="Windows bootstrap">/workspace/qa/src/db86ca0b4e82515795ccc1c5e32a55579582c0fe/tools/test_verifier_languages.py:83: Windows bootstrap</skipped></testcase><testcase classname="tools.test_verifier_languages" name="test_windows_missing_runtime_is_localized_before_python_starts[vi]" file="tools/test_verifier_languages.py" line="79" time="0.000"><skipped type="pytest.skip" message="Windows bootstrap">/workspace/qa/src/db86ca0b4e82515795ccc1c5e32a55579582c0fe/tools/test_verifier_languages.py:83: Windows bootstrap</skipped></testcase><testcase classname="tools.test_verifier_languages" name="test_windows_missing_runtime_is_localized_before_python_starts[zh]" file="tools/test_verifier_languages.py" line="79" time="0.001"><skipped type="pytest.skip" message="Windows bootstrap">/workspace/qa/src/db86ca0b4e82515795ccc1c5e32a55579582c0fe/tools/test_verifier_languages.py:83: Windows bootstrap</skipped></testcase><testcase classname="tools.test_verifier_languages" name="test_windows_missing_runtime_is_localized_before_python_starts[fr]" file="tools/test_verifier_languages.py" line="79" time="0.000"><skipped type="pytest.skip" message="Windows bootstrap">/workspace/qa/src/db86ca0b4e82515795ccc1c5e32a55579582c0fe/tools/test_verifier_languages.py:83: Windows bootstrap</skipped></testcase><testcase classname="tools.test_verifier_languages" name="test_windows_missing_runtime_is_localized_before_python_starts[de]" file="tools/test_verifier_languages.py" line="79" time="0.000"><skipped type="pytest.skip" message="Windows bootstrap">/workspace/qa/src/db86ca0b4e82515795ccc1c5e32a55579582c0fe/tools/test_verifier_languages.py:83: Windows bootstrap</skipped></testcase><testcase classname="tools.test_verifier_languages" name="test_windows_missing_runtime_is_localized_before_python_starts[it]" file="tools/test_verifier_languages.py" line="79" time="0.000"><skipped type="pytest.skip" message="Windows bootstrap">/workspace/qa/src/db86ca0b4e82515795ccc1c5e32a55579582c0fe/tools/test_verifier_languages.py:83: Windows bootstrap</skipped></testcase><testcase classname="tools.test_verifier_languages" name="test_windows_missing_runtime_is_localized_before_python_starts[uz]" file="tools/test_verifier_languages.py" line="79" time="0.000"><skipped type="pytest.skip" message="Windows bootstrap">/workspace/qa/src/db86ca0b4e82515795ccc1c5e32a55579582c0fe/tools/test_verifier_languages.py:83: Windows bootstrap</skipped></testcase><testcase classname="tools.test_verifier_languages" name="test_windows_missing_runtime_is_localized_before_python_starts[ko]" file="tools/test_verifier_languages.py" line="79" time="0.000"><skipped type="pytest.skip" message="Windows bootstrap">/workspace/qa/src/db86ca0b4e82515795ccc1c5e32a55579582c0fe/tools/test_verifier_languages.py:83: Windows bootstrap</skipped></testcase><testcase classname="tools.test_verifier_languages" name="test_windows_missing_runtime_is_localized_before_python_starts[zh-Hant]" file="tools/test_verifier_languages.py" line="79" time="0.000"><skipped type="pytest.skip" message="Windows bootstrap">/workspace/qa/src/db86ca0b4e82515795ccc1c5e32a55579582c0fe/tools/test_verifier_languages.py:83: Windows bootstrap</skipped></testcase><testcase classname="tools.test_verifier_languages" name="test_windows_missing_runtime_is_localized_before_python_starts[ms]" file="tools/test_verifier_languages.py" line="79" time="0.000"><skipped type="pytest.skip" message="Windows bootstrap">/workspace/qa/src/db86ca0b4e82515795ccc1c5e32a55579582c0fe/tools/test_verifier_languages.py:83: Windows bootstrap</skipped></testcase><testcase classname="tools.test_verifier_languages" name="test_windows_missing_runtime_is_localized_before_python_starts[pl]" file="tools/test_verifier_languages.py" line="79" time="0.000"><skipped type="pytest.skip" message="Windows bootstrap">/workspace/qa/src/db86ca0b4e82515795ccc1c5e32a55579582c0fe/tools/test_verifier_languages.py:83: Windows bootstrap</skipped></testcase><testcase classname="tools.test_verifier_languages" name="test_windows_missing_runtime_is_localized_before_python_starts[ja]" file="tools/test_verifier_languages.py" line="79" time="0.000"><skipped type="pytest.skip" message="Windows bootstrap">/workspace/qa/src/db86ca0b4e82515795ccc1c5e32a55579582c0fe/tools/test_verifier_languages.py:83: Windows bootstrap</skipped></testcase><testcase classname="tools.test_verifier_languages" name="test_windows_missing_runtime_is_localized_before_python_starts[th]" file="tools/test_verifier_languages.py" line="79" time="0.000"><skipped type="pytest.skip" message="Windows bootstrap">/workspace/qa/src/db86ca0b4e82515795ccc1c5e32a55579582c0fe/tools/test_verifier_languages.py:83: Windows bootstrap</skipped></testcase><testcase classname="tools.test_verifier_languages" name="test_windows_missing_runtime_is_localized_before_python_starts[he]" file="tools/test_verifier_languages.py" line="79" time="0.001"><skipped type="pytest.skip" message="Windows bootstrap">/workspace/qa/src/db86ca0b4e82515795ccc1c5e32a55579582c0fe/tools/test_verifier_languages.py:83: Windows bootstrap</skipped></testcase><testcase classname="tools.test_verifier_languages" name="test_windows_missing_runtime_is_localized_before_python_starts[bn]" file="tools/test_verifier_languages.py" line="79" time="0.000"><skipped type="pytest.skip" message="Windows bootstrap">/workspace/qa/src/db86ca0b4e82515795ccc1c5e32a55579582c0fe/tools/test_verifier_languages.py:83: Windows bootstrap</skipped></testcase><testcase classname="tools.test_verifier_languages" name="test_windows_missing_runtime_is_localized_before_python_starts[ru]" file="tools/test_verifier_languages.py" line="79" time="0.000"><skipped type="pytest.skip" message="Windows bootstrap">/workspace/qa/src/db86ca0b4e82515795ccc1c5e32a55579582c0fe/tools/test_verifier_languages.py:83: Windows bootstrap</skipped></testcase><testcase classname="tools.test_verifier_languages" name="test_export_launchers_and_instructions_retain_the_selected_language[en]" file="tools/test_verifier_languages.py" line="94" time="0.000" /><testcase classname="tools.test_verifier_languages" name="test_export_launchers_and_instructions_retain_the_selected_language[uk]" file="tools/test_verifier_languages.py" line="94" time="0.000" /><testcase classname="tools.test_verifier_languages" name="test_export_launchers_and_instructions_retain_the_selected_language[es]" file="tools/test_verifier_languages.py" line="94" time="0.000" /><testcase classname="tools.test_verifier_languages" name="test_export_launchers_and_instructions_retain_the_selected_language[pt]" file="tools/test_verifier_languages.py" line="94" time="0.000" /><testcase classname="tools.test_verifier_languages" name="test_export_launchers_and_instructions_retain_the_selected_language[tr]" file="tools/test_verifier_languages.py" line="94" time="0.000" /><testcase classname="tools.test_verifier_languages" name="test_export_launchers_and_instructions_retain_the_selected_language[ar]" file="tools/test_verifier_languages.py" line="94" time="0.000" /><testcase classname="tools.test_verifier_languages" name="test_export_launchers_and_instructions_retain_the_selected_language[fa]" file="tools/test_verifier_languages.py" line="94" time="0.000" /><testcase classname="tools.test_verifier_languages" name="test_export_launchers_and_instructions_retain_the_selected_language[ur]" file="tools/test_verifier_languages.py" line="94" time="0.000" /><testcase classname="tools.test_verifier_languages" name="test_export_launchers_and_instructions_retain_the_selected_language[hi]" file="tools/test_verifier_languages.py" line="94" time="0.000" /><testcase classname="tools.test_verifier_languages" name="test_export_launchers_and_instructions_retain_the_selected_language[id]" file="tools/test_verifier_languages.py" line="94" time="0.000" /><testcase classname="tools.test_verifier_languages" name="test_export_launchers_and_instructions_retain_the_selected_language[vi]" file="tools/test_verifier_languages.py" line="94" time="0.000" /><testcase classname="tools.test_verifier_languages" name="test_export_launchers_and_instructions_retain_the_selected_language[zh]" file="tools/test_verifier_languages.py" line="94" time="0.000" /><testcase classname="tools.test_verifier_languages" name="test_export_launchers_and_instructions_retain_the_selected_language[fr]" file="tools/test_verifier_languages.py" line="94" time="0.000" /><testcase classname="tools.test_verifier_languages" name="test_export_launchers_and_instructions_retain_the_selected_language[de]" file="tools/test_verifier_languages.py" line="94" time="0.000" /><testcase classname="tools.test_verifier_languages" name="test_export_launchers_and_instructions_retain_the_selected_language[it]" file="tools/test_verifier_languages.py" line="94" time="0.000" /><testcase classname="tools.test_verifier_languages" name="test_export_launchers_and_instructions_retain_the_selected_language[uz]" file="tools/test_verifier_languages.py" line="94" time="0.000" /><testcase classname="tools.test_verifier_languages" name="test_export_launchers_and_instructions_retain_the_selected_language[ko]" file="tools/test_verifier_languages.py" line="94" time="0.000" /><testcase classname="tools.test_verifier_languages" name="test_export_launchers_and_instructions_retain_the_selected_language[zh-Hant]" file="tools/test_verifier_languages.py" line="94" time="0.000" /><testcase classname="tools.test_verifier_languages" name="test_export_launchers_and_instructions_retain_the_selected_language[ms]" file="tools/test_verifier_languages.py" line="94" time="0.000" /><testcase classname="tools.test_verifier_languages" name="test_export_launchers_and_instructions_retain_the_selected_language[pl]" file="tools/test_verifier_languages.py" line="94" time="0.000" /><testcase classname="tools.test_verifier_languages" name="test_export_launchers_and_instructions_retain_the_selected_language[ja]" file="tools/test_verifier_languages.py" line="94" time="0.000" /><testcase classname="tools.test_verifier_languages" name="test_export_launchers_and_instructions_retain_the_selected_language[th]" file="tools/test_verifier_languages.py" line="94" time="0.000" /><testcase classname="tools.test_verifier_languages" name="test_export_launchers_and_instructions_retain_the_selected_language[he]" file="tools/test_verifier_languages.py" line="94" time="0.000" /><testcase classname="tools.test_verifier_languages" name="test_export_launchers_and_instructions_retain_the_selected_language[bn]" file="tools/test_verifier_languages.py" line="94" time="0.000" /><testcase classname="tools.test_verifier_languages" name="test_export_launchers_and_instructions_retain_the_selected_language[ru]" file="tools/test_verifier_languages.py" line="94" time="0.000" /><testcase classname="tools.test_verifier_languages" name="test_language_tags_and_os_detection[de-DE-de]" file="tools/test_verifier_languages.py" line="106" time="0.000" /><testcase classname="tools.test_verifier_languages" name="test_language_tags_and_os_detection[pt_BR.UTF-8-pt]" file="tools/test_verifier_languages.py" line="106" time="0.000" /><testcase classname="tools.test_verifier_languages" name="test_language_tags_and_os_detection[zh_TW.UTF-8-zh-Hant]" file="tools/test_verifier_languages.py" line="106" time="0.000" /><testcase classname="tools.test_verifier_languages" name="test_language_tags_and_os_detection[zh-HK-zh-Hant]" file="tools/test_verifier_languages.py" line="106" time="0.000" /><testcase classname="tools.test_verifier_languages" name="test_language_tags_and_os_detection[zh-Hans-zh]" file="tools/test_verifier_languages.py" line="106" time="0.000" /><testcase classname="tools.test_verifier_languages" name="test_language_tags_and_os_detection[Arabic_Egypt-ar]" file="tools/test_verifier_languages.py" line="106" time="0.000" /><testcase classname="tools.test_verifier_languages" name="test_language_tags_and_os_detection[Japanese_Japan-ja]" file="tools/test_verifier_languages.py" line="106" time="0.000" /><testcase classname="tools.test_verifier_languages" name="test_language_tags_and_os_detection[ru_RU-ru]" file="tools/test_verifier_languages.py" line="106" time="0.000" /><testcase classname="tools.test_verifier_languages" name="test_language_tags_and_os_detection[Russian_Russia-ru]" file="tools/test_verifier_languages.py" line="106" time="0.000" /><testcase classname="tools.test_verifier_languages" name="test_language_tags_and_os_detection[Ukrainian_Ukraine-uk]" file="tools/test_verifier_languages.py" line="106" time="0.000" /><testcase classname="tools.test_verifier_languages" name="test_language_tags_and_os_detection[Bengali_Bangladesh-bn]" file="tools/test_verifier_languages.py" line="106" time="0.000" /><testcase classname="tools.test_verifier_languages" name="test_language_choice_retries_without_shell_evaluation" file="tools/test_verifier_languages.py" line="117" time="0.001" /><testcase classname="tools.test_verifier_languages" name="test_every_language_is_bound_into_actual_signed_exports" file="tools/test_verifier_languages.py" line="128" time="0.827" /><testcase classname="tools.test_verifier_output_safety" name="test_signature_before_format_and_before_required_payload_fields[verify_witness]" file="tools/test_verifier_output_safety.py" line="30" time="0.037" /><testcase classname="tools.test_verifier_output_safety" name="test_signature_before_format_and_before_required_payload_fields[verify_chat_export]" file="tools/test_verifier_output_safety.py" line="30" time="0.026" /><testcase classname="tools.test_verifier_output_safety" name="test_future_format_exit_codes" file="tools/test_verifier_output_safety.py" line="38" time="0.225" /><testcase classname="tools.test_verifier_output_safety" name="test_unpinned_is_explicit_and_strict_is_opt_in" file="tools/test_verifier_output_safety.py" line="48" time="0.350" /><testcase classname="tools.test_verifier_output_safety" name="test_all_c0_c1_controls_removed_except_newline_tab" file="tools/test_verifier_output_safety.py" line="63" time="0.000" /><testcase classname="tools.test_verifier_output_safety" name="test_console_cannot_execute_package_escape_sequences" file="tools/test_verifier_output_safety.py" line="69" time="0.000" /><testcase classname="tools.test_verifier_output_safety" name="test_comparison_checks_both_pins_and_sanitizes_its_separate_output_path" file="tools/test_verifier_output_safety.py" line="82" time="0.271" /><testcase classname="tools.test_verifier_output_safety" name="test_comparison_authenticated_future_format_keeps_strict_exit_three" file="tools/test_verifier_output_safety.py" line="99" time="0.089" /><testcase classname="tools.test_verifier_sources" name="test_committed_verifier_matches_reviewed_sources" file="tools/test_verifier_sources.py" line="90" time="0.391" /><testcase classname="tools.test_verifier_sources" name="test_builder_rejects_ambiguous_directives[from ..outside import anything\n]" file="tools/test_verifier_sources.py" line="97" time="0.001" /><testcase classname="tools.test_verifier_sources" name="test_builder_rejects_ambiguous_directives[from .chain import *\n]" file="tools/test_verifier_sources.py" line="97" time="0.000" /><testcase classname="tools.test_verifier_sources" name="test_builder_rejects_ambiguous_directives[from .chain import canonical as changed\n]" file="tools/test_verifier_sources.py" line="97" time="0.000" /><testcase classname="tools.test_verifier_sources" name="test_builder_rejects_ambiguous_directives[from .chain import canonical; raise RuntimeError()\n]" file="tools/test_verifier_sources.py" line="97" time="0.000" /><testcase classname="tools.test_verifier_sources" name="test_builder_rejects_ambiguous_directives[if True: from .chain import canonical\n]" file="tools/test_verifier_sources.py" line="97" time="0.000" /><testcase classname="tools.test_verifier_sources" name="test_builder_rejects_ambiguous_directives[def f():\n    __all__ = []\n]" file="tools/test_verifier_sources.py" line="97" time="0.000" /><testcase classname="tools.test_verifier_sources" name="test_review_modules_import_without_application_state" file="tools/test_verifier_sources.py" line="107" time="0.004"><failure message="AssertionError: assert False&#10;[+2 more lines; full report in element text]">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())
&gt;       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}, ...}, ...} = &lt;function verify_bundle at 0x747f79b03060&gt;(PosixPath('/workspace/qa/src/db86ca0b4e82515795ccc1c5e32a55579582c0fe/tools/fixtures/evidence-before-refactor.zip'), '56475aa75463474c0285df5dbf2bcab73da651358839e9b77481b2eab107708c')

tools/test_verifier_sources.py:113: AssertionError</failure></testcase><testcase classname="tools.test_verifier_sources" name="test_frozen_verification_decisions_are_unchanged" file="tools/test_verifier_sources.py" line="115" time="0.136"><failure message="assert False&#10;[+2 more lines; full report in element text]">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
&gt;       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/db86ca0b4e82515795cc...uested_checks_unavailable": []\n  },\n  "evidence_profile": "integrity",\n  "requirements_met": true\n}\n', stderr=b'').stdout

tools/test_verifier_sources.py:121: AssertionError</failure></testcase><testcase classname="tools.test_verifier_sources" name="test_old_and_new_decisions_and_statuses_match[pinned---json]" file="tools/test_verifier_sources.py" line="123" time="0.245"><failure message="assert False&#10;[+3 more lines; full report in element text]">previous = PosixPath('/tmp/pytest-of-root/pytest-6/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':
&gt;           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/db86ca0b4e82515795cc...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-6/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</failure></testcase><testcase classname="tools.test_verifier_sources" name="test_old_and_new_decisions_and_statuses_match[pinned---plain]" file="tools/test_verifier_sources.py" line="123" time="0.244"><failure message="assert False&#10;[+5 more lines; full report in element text]">previous = PosixPath('/tmp/pytest-of-root/pytest-6/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:
&gt;           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/db86ca0b4e82515795cc... 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-6/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</failure></testcase><testcase classname="tools.test_verifier_sources" name="test_old_and_new_decisions_and_statuses_match[pinned---pretty]" file="tools/test_verifier_sources.py" line="123" time="0.252" /><testcase classname="tools.test_verifier_sources" name="test_old_and_new_decisions_and_statuses_match[unpinned---json]" file="tools/test_verifier_sources.py" line="123" time="0.246"><failure message="assert False&#10;[+3 more lines; full report in element text]">previous = PosixPath('/tmp/pytest-of-root/pytest-6/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':
&gt;           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/db86ca0b4e82515795cc...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-6/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</failure></testcase><testcase classname="tools.test_verifier_sources" name="test_old_and_new_decisions_and_statuses_match[unpinned---plain]" file="tools/test_verifier_sources.py" line="123" time="0.255"><failure message="assert False&#10;[+5 more lines; full report in element text]">previous = PosixPath('/tmp/pytest-of-root/pytest-6/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:
&gt;           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/db86ca0b4e82515795cc... 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-6/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</failure></testcase><testcase classname="tools.test_verifier_sources" name="test_old_and_new_decisions_and_statuses_match[unpinned---pretty]" file="tools/test_verifier_sources.py" line="123" time="0.246" /><testcase classname="tools.test_verifier_sources" name="test_old_and_new_decisions_and_statuses_match[wrong_key---json]" file="tools/test_verifier_sources.py" line="123" time="0.246" /><testcase classname="tools.test_verifier_sources" name="test_old_and_new_decisions_and_statuses_match[wrong_key---plain]" file="tools/test_verifier_sources.py" line="123" time="0.240" /><testcase classname="tools.test_verifier_sources" name="test_old_and_new_decisions_and_statuses_match[wrong_key---pretty]" file="tools/test_verifier_sources.py" line="123" time="0.241" /><testcase classname="tools.test_verifier_sources" name="test_old_and_new_decisions_and_statuses_match[unmet_tier---json]" file="tools/test_verifier_sources.py" line="123" time="0.244"><failure message="assert False&#10;[+3 more lines; full report in element text]">previous = PosixPath('/tmp/pytest-of-root/pytest-6/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':
&gt;           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/db86ca0b4e82515795cc...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-6/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</failure></testcase><testcase classname="tools.test_verifier_sources" name="test_old_and_new_decisions_and_statuses_match[unmet_tier---plain]" file="tools/test_verifier_sources.py" line="123" time="0.250"><failure message="assert False&#10;[+5 more lines; full report in element text]">previous = PosixPath('/tmp/pytest-of-root/pytest-6/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:
&gt;           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/db86ca0b4e82515795cc... 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-6/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</failure></testcase><testcase classname="tools.test_verifier_sources" name="test_old_and_new_decisions_and_statuses_match[unmet_tier---pretty]" file="tools/test_verifier_sources.py" line="123" time="0.247" /><testcase classname="tools.test_verifier_sources" name="test_old_and_new_rejections_match[signature]" file="tools/test_verifier_sources.py" line="145" time="0.238" /><testcase classname="tools.test_verifier_sources" name="test_old_and_new_rejections_match[newer_format]" file="tools/test_verifier_sources.py" line="145" time="0.240" /><testcase classname="tools.test_verifier_sources" name="test_old_verifier_accepts_new_archive_with_identical_signed_events" file="tools/test_verifier_sources.py" line="170" time="0.486"><failure message="assert False&#10;[+3 more lines; full report in element text]">previous = PosixPath('/tmp/pytest-of-root/pytest-6/test_old_verifier_accepts_new_0/previous.py')
tmp_path = PosixPath('/tmp/pytest-of-root/pytest-6/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
&gt;           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/db86ca0b4e82515795cc...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-6/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</failure></testcase><testcase classname="tools.test_video_documentation" name="test_steps_get_their_moment_and_subtitles_follow_the_recording" file="tools/test_video_documentation.py" line="33" time="0.204" /><testcase classname="tools.test_video_documentation" name="test_a_second_recording_takes_over_from_its_start" file="tools/test_video_documentation.py" line="57" time="0.190" /><testcase classname="tools.test_video_documentation" name="test_case_package_carries_subtitles_and_revisions_keep_the_recording" file="tools/test_video_documentation.py" line="70" time="0.254" /><testcase classname="tools.test_video_documentation" name="test_without_a_recording_nothing_changes" file="tools/test_video_documentation.py" line="87" time="0.229" /><testcase classname="tools.test_watchlists" name="test_terms_patterns_wallets_usernames_and_domains_are_matched" file="tools/test_watchlists.py" line="44" time="0.297"><failure message="assert False&#10; +  where False = all(&lt;generator object test_terms_patterns_wallets_usernames_and_domains_are_matched.&lt;locals&gt;.&lt;genexpr&gt; at 0x747f7bd959a0&gt;)">store = &lt;tgwitness.store.Store object at 0x747f7a6859a0&gt;

    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"}
&gt;       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(&lt;generator object test_terms_patterns_wallets_usernames_and_domains_are_matched.&lt;locals&gt;.&lt;genexpr&gt; at 0x747f7bd959a0&gt;)

tools/test_watchlists.py:61: AssertionError</failure></testcase><testcase classname="tools.test_watchlists" name="test_a_term_matches_whole_words_and_a_subdomain_counts_for_its_domain" file="tools/test_watchlists.py" line="63" time="0.272" /><testcase classname="tools.test_watchlists" name="test_matches_in_buttons_hidden_links_and_qr_codes_are_found" file="tools/test_watchlists.py" line="72" time="0.250" /><testcase classname="tools.test_watchlists" name="test_a_list_can_be_limited_to_chosen_chats" file="tools/test_watchlists.py" line="85" time="0.260" /><testcase classname="tools.test_watchlists" name="test_scanning_is_incremental_and_never_records_the_same_hit_twice" file="tools/test_watchlists.py" line="93" time="0.284" /><testcase classname="tools.test_watchlists" name="test_excerpts_are_off_until_the_list_asks_for_them" file="tools/test_watchlists.py" line="107" time="0.256" /><testcase classname="tools.test_watchlists" name="test_entries_import_and_export_as_plain_lines" file="tools/test_watchlists.py" line="119" time="0.200" /><testcase classname="tools.test_watchlists" name="test_statistics_count_hits_per_entry" file="tools/test_watchlists.py" line="130" time="0.297" /><testcase classname="tools.test_watchlists" name="test_invalid_entries[body0]" file="tools/test_watchlists.py" line="141" time="0.000" /><testcase classname="tools.test_watchlists" name="test_invalid_entries[body1]" file="tools/test_watchlists.py" line="141" time="0.000" /><testcase classname="tools.test_watchlists" name="test_invalid_entries[body2]" file="tools/test_watchlists.py" line="141" time="0.000" /><testcase classname="tools.test_watchlists" name="test_invalid_entries[body3]" file="tools/test_watchlists.py" line="141" time="0.000" /><testcase classname="tools.test_watchlists" name="test_invalid_entries[body4]" file="tools/test_watchlists.py" line="141" time="0.000" /><testcase classname="tools.test_watchlists" name="test_invalid_entries[body5]" file="tools/test_watchlists.py" line="141" time="0.000" /><testcase classname="tools.test_watchlists" name="test_invalid_entries[body6]" file="tools/test_watchlists.py" line="141" time="0.000" /><testcase classname="tools.test_watchlists" name="test_watchlists_are_off_for_the_evidence_goal" file="tools/test_watchlists.py" line="150" time="0.233" /><testcase classname="tools.test_watchlists" name="test_the_protocol_states_that_a_match_is_the_investigators_choice" file="tools/test_watchlists.py" line="158" time="0.220" /><testcase classname="tools.test_webapp" name="test_relative_addresses_resolve_against_the_page" file="tools/test_webapp.py" line="35" time="0.001" /><testcase classname="tools.test_webapp" name="test_script_literals_and_calls_are_collected" file="tools/test_webapp.py" line="42" time="0.000" /><testcase classname="tools.test_webapp" name="test_inline_and_non_network_schemes_are_ignored" file="tools/test_webapp.py" line="48" time="0.000" /><testcase classname="tools.test_webapp" name="test_third_party_hosts_are_separated_from_the_origin" file="tools/test_webapp.py" line="54" time="0.000" /><testcase classname="tools.test_webapp" name="test_websocket_endpoints_are_listed" file="tools/test_webapp.py" line="61" time="0.000" /><testcase classname="tools.test_webapp" name="test_same_origin_flag_matches_the_page_origin" file="tools/test_webapp.py" line="65" time="0.000" /><testcase classname="tools.test_webapp" name="test_an_address_seen_twice_keeps_both_sources_once" file="tools/test_webapp.py" line="71" time="0.000" /><testcase classname="tools.test_webapp" name="test_the_record_states_that_this_is_one_response" file="tools/test_webapp.py" line="79" time="0.000" /><testcase classname="tools.test_webapp" name="test_parsing_is_bounded" file="tools/test_webapp.py" line="85" time="0.024" /><testcase classname="tools.test_webapp" name="test_buttons_are_read_from_a_signed_payload" file="tools/test_webapp.py" line="91" time="0.000" /><testcase classname="tools.test_webapp" name="test_endpoints_become_indicators" file="tools/test_webapp.py" line="99" time="0.001" /><testcase classname="tools.test_webapp" name="test_inspect_refuses_a_workspace_without_an_outside_route" file="tools/test_webapp.py" line="106" time="0.001" /><testcase classname="tools.test_webapp" name="test_inspect_rejects_an_address_that_is_not_http" file="tools/test_webapp.py" line="113" time="0.001" /><testcase classname="tools.test_webapp" name="test_inspect_uses_the_outside_route_and_records_what_it_fetched" file="tools/test_webapp.py" line="120" time="0.001" /><testcase classname="tools.test_witness_continuity" name="test_rewritten_1000_record_prefix_is_rejected_when_the_journal_grows_to_1100" file="tools/test_witness_continuity.py" line="14" time="5.092" /><testcase classname="tools.test_witness_daily" name="test_two_days_chain_and_pending_is_not_confirmed" file="tools/test_witness_daily.py" line="46" time="0.346" /><testcase classname="tools.test_witness_daily" name="test_missing_middle_day_remains_visible" file="tools/test_witness_daily.py" line="57" time="0.320" /><testcase classname="tools.test_witness_daily" name="test_resigned_wrong_daily_fields_fail[corrupt0]" file="tools/test_witness_daily.py" line="62" time="0.221" /><testcase classname="tools.test_witness_daily" name="test_resigned_wrong_daily_fields_fail[corrupt1]" file="tools/test_witness_daily.py" line="62" time="0.233" /><testcase classname="tools.test_witness_daily" name="test_resigned_wrong_daily_fields_fail[corrupt2]" file="tools/test_witness_daily.py" line="62" time="0.223" /><testcase classname="tools.test_witness_daily" name="test_resigned_wrong_daily_fields_fail[corrupt3]" file="tools/test_witness_daily.py" line="62" time="0.232" /><testcase classname="tools.test_witness_daily" name="test_empty_previous_day_does_not_claim_a_successful_check" file="tools/test_witness_daily.py" line="69" time="0.267" /><testcase classname="tools.test_witness_daily" name="test_bitcoin_path_must_match_external_header" file="tools/test_witness_daily.py" line="85" time="0.000" /><testcase classname="tools.test_witness_daily" name="test_daily_upgrade_retains_original_and_stays_unconfirmed_offline" file="tools/test_witness_daily.py" line="96" time="0.508" /><testcase classname="tools.test_witness_daily" name="test_failed_submission_retries_after_restart_without_rewriting_the_daily_seal" file="tools/test_witness_daily.py" line="116" time="0.396" /><testcase classname="tools.test_witness_daily" name="test_failed_submission_retry_is_bounded_and_rotates_between_old_seals" file="tools/test_witness_daily.py" line="149" time="0.415" /><testcase classname="tools.test_witness_export_window" name="test_records_appended_while_the_export_was_built_are_not_a_conflict" file="tools/test_witness_export_window.py" line="27" time="0.000" /><testcase classname="tools.test_witness_export_window" name="test_records_the_witness_saw_before_the_snapshot_are_a_conflict" file="tools/test_witness_export_window.py" line="33" time="0.000" /><testcase classname="tools.test_witness_export_window" name="test_an_older_manifest_without_a_snapshot_time_still_uses_created_at" file="tools/test_witness_export_window.py" line="39" time="0.000" /><testcase classname="tools.test_witness_export_window" name="test_an_accepted_key_change_inside_the_export_is_not_an_anomaly" file="tools/test_witness_export_window.py" line="45" time="0.000" /><testcase classname="tools.test_witness_export_window" name="test_an_unexplained_bad_status_inside_the_export_is_still_an_anomaly" file="tools/test_witness_export_window.py" line="52" time="0.001" /><testcase classname="tools.test_witness_freshness" name="test_deterministic_challenge_and_offline_does_not_claim_external_time" file="tools/test_witness_freshness.py" line="42" time="0.546" /><testcase classname="tools.test_witness_freshness" name="test_tampered_binding_fails_even_if_witness_resigns[change0]" file="tools/test_witness_freshness.py" line="51" time="0.483" /><testcase classname="tools.test_witness_freshness" name="test_tampered_binding_fails_even_if_witness_resigns[change1]" file="tools/test_witness_freshness.py" line="51" time="0.502" /><testcase classname="tools.test_witness_freshness" name="test_tampered_binding_fails_even_if_witness_resigns[change2]" file="tools/test_witness_freshness.py" line="51" time="0.552" /><testcase classname="tools.test_witness_freshness" name="test_tampered_binding_fails_even_if_witness_resigns[change3]" file="tools/test_witness_freshness.py" line="51" time="0.530" /><testcase classname="tools.test_witness_freshness" name="test_relay_mismatch_fails_and_unavailable_is_absent" file="tools/test_witness_freshness.py" line="58" time="0.545" /><testcase classname="tools.test_witness_freshness" name="test_legacy_anchor_has_no_freshness_credit" file="tools/test_witness_freshness.py" line="74" time="0.519" /><testcase classname="tools.test_witness_freshness" name="test_latest_rejects_future_invalid_and_network_errors" file="tools/test_witness_freshness.py" line="78" time="0.001" /><testcase classname="tools.test_witness_freshness" name="test_http_fetch_binds_nonce_and_fallback_clears_previous" file="tools/test_witness_freshness.py" line="87" time="0.202" /><testcase classname="tools.test_witness_keys" name="test_signed_authorization_history_and_unpinned_witness_change_detection[created]" file="tools/test_witness_keys.py" line="14" time="0.564" /><testcase classname="tools.test_witness_keys" name="test_signed_authorization_history_and_unpinned_witness_change_detection[imported]" file="tools/test_witness_keys.py" line="14" time="0.477" /><testcase classname="tools.test_witness_keys" name="test_signed_authorization_history_and_unpinned_witness_change_detection[None]" file="tools/test_witness_keys.py" line="14" time="0.466" /><testcase classname="tools.test_witness_keys" name="test_legacy_capture_without_keys_and_invalid_keys" file="tools/test_witness_keys.py" line="43" time="0.185" /><testcase classname="tools.test_witness_relogin" name="test_relogin_is_recorded_once_then_accepted_with_continuity" file="tools/test_witness_relogin.py" line="78" time="0.561" /><testcase classname="tools.test_witness_relogin" name="test_rollback_after_relogin_is_not_masked_as_key_change" file="tools/test_witness_relogin.py" line="88" time="0.516" /><testcase classname="tools.test_witness_relogin" name="test_older_export_is_not_contradicted_by_a_later_relogin" file="tools/test_witness_relogin.py" line="118" time="0.652" /><testcase classname="tools.test_witness_relogin" name="test_newer_export_accepts_a_verified_key_change_inside_its_range" file="tools/test_witness_relogin.py" line="133" time="0.692" /><testcase classname="tools.test_witness_relogin" name="test_export_ending_before_records_the_witness_saw_earlier_is_a_conflict" file="tools/test_witness_relogin.py" line="143" time="0.682" /><testcase classname="tools.test_witness_resilience" name="test_rejected_or_failed_head_requests_are_not_recorded_as_polls" file="tools/test_witness_resilience.py" line="32" time="0.210" /><testcase classname="tools.test_witness_resilience" name="test_alternating_fingerprints_are_journaled_once_per_pair_and_bounded" file="tools/test_witness_resilience.py" line="48" time="0.550" /><testcase classname="tools.test_witness_resilience" name="test_legacy_poll_fingerprint_is_not_journaled_again" file="tools/test_witness_resilience.py" line="62" time="0.184" /><testcase classname="tools.test_witness_resilience" name="test_interval_header_is_parsed_without_server_errors[\xb2-None]" file="tools/test_witness_resilience.py" line="69" time="0.180" /><testcase classname="tools.test_witness_resilience" name="test_interval_header_is_parsed_without_server_errors[\xb9\u2070-None]" file="tools/test_witness_resilience.py" line="69" time="0.182" /><testcase classname="tools.test_witness_resilience" name="test_interval_header_is_parsed_without_server_errors[15-15]" file="tools/test_witness_resilience.py" line="69" time="0.185" /><testcase classname="tools.test_witness_resilience" name="test_interval_header_is_parsed_without_server_errors[0-None]" file="tools/test_witness_resilience.py" line="69" time="0.179" /><testcase classname="tools.test_witness_resilience" name="test_interval_header_is_parsed_without_server_errors[1441-None]" file="tools/test_witness_resilience.py" line="69" time="0.186" /><testcase classname="tools.test_witness_resilience" name="test_interval_header_is_parsed_without_server_errors[99999-None]" file="tools/test_witness_resilience.py" line="69" time="0.242" /><testcase classname="tools.test_witness_resilience" name="test_interval_header_is_parsed_without_server_errors[-None]" file="tools/test_witness_resilience.py" line="69" time="0.200" /><testcase classname="tools.test_witness_resilience" name="test_poll_without_interval_counts_only_while_recent" file="tools/test_witness_resilience.py" line="77" time="0.000" /><testcase classname="tools.test_witness_resilience" name="test_daily_and_timestamp_failures_are_recorded_without_stopping" file="tools/test_witness_resilience.py" line="95" time="0.218" /><testcase classname="tools.test_witness_resilience" name="test_backwards_clock_after_a_daily_seal_keeps_the_journal_verifiable" file="tools/test_witness_resilience.py" line="111" time="0.283" /><testcase classname="tools.test_witness_resilience" name="test_interrupted_migration_removes_a_matching_plaintext_key" file="tools/test_witness_resilience.py" line="142" time="0.015" /><testcase classname="tools.test_witness_resilience" name="test_differing_plaintext_and_sealed_keys_refuse_to_start" file="tools/test_witness_resilience.py" line="151" time="0.030" /><testcase classname="tools.test_witness_resilience" name="test_plaintext_only_key_is_still_migrated" file="tools/test_witness_resilience.py" line="167" time="0.027" /><testcase classname="addons.capture.tests.test_beacon" name="test_signed_copies_do_not_replace_independent_beacon_queries" file="addons/capture/tests/test_beacon.py" line="17" time="0.000" /><testcase classname="addons.capture.tests.test_beacon" name="test_other_chains_and_replayed_rounds_rejected" file="addons/capture/tests/test_beacon.py" line="30" time="0.000" /><testcase classname="addons.capture.tests.test_beacon" name="test_browser_records_fresh_beacon_through_owned_proxy_context" file="addons/capture/tests/test_beacon.py" line="39" time="0.055" /><testcase classname="addons.capture.tests.test_gateway" name="test_destination_boundaries[localhost:443]" file="addons/capture/tests/test_gateway.py" line="10" time="0.000" /><testcase classname="addons.capture.tests.test_gateway" name="test_destination_boundaries[127.0.0.1:443]" file="addons/capture/tests/test_gateway.py" line="10" time="0.000" /><testcase classname="addons.capture.tests.test_gateway" name="test_destination_boundaries[[::1]:443]" file="addons/capture/tests/test_gateway.py" line="10" time="0.000" /><testcase classname="addons.capture.tests.test_gateway" name="test_destination_boundaries[169.254.169.254:443]" file="addons/capture/tests/test_gateway.py" line="10" time="0.000" /><testcase classname="addons.capture.tests.test_gateway" name="test_destination_boundaries[web.telegram.org:80]" file="addons/capture/tests/test_gateway.py" line="10" time="0.000" /><testcase classname="addons.capture.tests.test_gateway" name="test_destination_boundaries[web.telegram.org.evil:443]" file="addons/capture/tests/test_gateway.py" line="10" time="0.000" /><testcase classname="addons.capture.tests.test_gateway" name="test_destination_boundaries[evil:443]" file="addons/capture/tests/test_gateway.py" line="10" time="0.000" /><testcase classname="addons.capture.tests.test_gateway" name="test_destination_boundaries[web.telegram.org:443\r\nInjected: true]" file="addons/capture/tests/test_gateway.py" line="10" time="0.000" /><testcase classname="addons.capture.tests.test_gateway" name="test_destination_boundaries[web.telegram.org:0]" file="addons/capture/tests/test_gateway.py" line="10" time="0.000" /><testcase classname="addons.capture.tests.test_gateway" name="test_bridge_forwards_only_through_upstream_and_stops_on_failure" file="addons/capture/tests/test_gateway.py" line="18" time="1.004" /><testcase classname="addons.capture.tests.test_gateway" name="test_upstream_failure_never_attempts_direct_destination" file="addons/capture/tests/test_gateway.py" line="69" time="0.001" /><testcase classname="addons.capture.tests.test_official" name="test_origin_is_exact[https://web.telegram.org.evil/a/]" file="addons/capture/tests/test_official.py" line="16" time="0.001" /><testcase classname="addons.capture.tests.test_official" name="test_origin_is_exact[http://web.telegram.org/a/]" file="addons/capture/tests/test_official.py" line="16" time="0.001" /><testcase classname="addons.capture.tests.test_official" name="test_origin_is_exact[https://evil@web.telegram.org/a/]" file="addons/capture/tests/test_official.py" line="16" time="0.001" /><testcase classname="addons.capture.tests.test_official" name="test_origin_is_exact[https://web.telegram.org/k/]" file="addons/capture/tests/test_official.py" line="16" time="0.001" /><testcase classname="addons.capture.tests.test_official" name="test_origin_is_exact[https://web.telegram.org/a/?redirect=evil]" file="addons/capture/tests/test_official.py" line="16" time="0.001" /><testcase classname="addons.capture.tests.test_official" name="test_origin_is_exact[https://web.telegram.org:8443/a/]" file="addons/capture/tests/test_official.py" line="16" time="0.001" /><testcase classname="addons.capture.tests.test_official" name="test_invalid_or_unsafe_configuration[change0]" file="addons/capture/tests/test_official.py" line="24" time="0.001" /><testcase classname="addons.capture.tests.test_official" name="test_invalid_or_unsafe_configuration[change1]" file="addons/capture/tests/test_official.py" line="24" time="0.001" /><testcase classname="addons.capture.tests.test_official" name="test_invalid_or_unsafe_configuration[change2]" file="addons/capture/tests/test_official.py" line="24" time="0.001" /><testcase classname="addons.capture.tests.test_official" name="test_invalid_or_unsafe_configuration[change3]" file="addons/capture/tests/test_official.py" line="24" time="0.001" /><testcase classname="addons.capture.tests.test_official" name="test_invalid_or_unsafe_configuration[change4]" file="addons/capture/tests/test_official.py" line="24" time="0.001" /><testcase classname="addons.capture.tests.test_official" name="test_invalid_or_unsafe_configuration[change5]" file="addons/capture/tests/test_official.py" line="24" time="0.001" /><testcase classname="addons.capture.tests.test_official" name="test_invalid_or_unsafe_configuration[change6]" file="addons/capture/tests/test_official.py" line="24" time="0.001" /><testcase classname="addons.capture.tests.test_official" name="test_invalid_or_unsafe_configuration[change7]" file="addons/capture/tests/test_official.py" line="24" time="0.001" /><testcase classname="addons.capture.tests.test_official" name="test_invalid_or_unsafe_configuration[change8]" file="addons/capture/tests/test_official.py" line="24" time="0.000" /><testcase classname="addons.capture.tests.test_official" name="test_direct_requires_explicit_selection_and_rejects_proxy_secrets" file="addons/capture/tests/test_official.py" line="35" time="0.001" /><testcase classname="addons.capture.tests.test_official" name="test_named_api_authentication_validation_and_frozen_plan" file="addons/capture/tests/test_official.py" line="46" time="1.111" /><testcase classname="addons.capture.tests.test_official" name="test_egress_change_and_unavailable_probe_stop[False]" file="addons/capture/tests/test_official.py" line="74" time="0.054" /><testcase classname="addons.capture.tests.test_official" name="test_egress_change_and_unavailable_probe_stop[True]" file="addons/capture/tests/test_official.py" line="74" time="0.051" /><testcase classname="addons.capture.tests.test_official" name="test_official_panel_login_selection_export_and_languages[False]" file="addons/capture/tests/test_official.py" line="112" time="0.001"><skipped type="pytest.skip" message="Use --capture-browser for the real panel test">/workspace/qa/src/db86ca0b4e82515795ccc1c5e32a55579582c0fe/addons/capture/tests/test_official.py:116: Use --capture-browser for the real panel test</skipped></testcase><testcase classname="addons.capture.tests.test_official" name="test_official_panel_login_selection_export_and_languages[True]" file="addons/capture/tests/test_official.py" line="112" time="0.000"><skipped type="pytest.skip" message="Use --capture-browser for the real panel test">/workspace/qa/src/db86ca0b4e82515795ccc1c5e32a55579582c0fe/addons/capture/tests/test_official.py:116: Use --capture-browser for the real panel test</skipped></testcase><testcase classname="addons.capture.tests.test_official" name="test_owned_browser_guard_scroll_capture_and_unknown_dialog" file="addons/capture/tests/test_official.py" line="233" time="0.000"><skipped type="pytest.skip" message="Use --capture-browser for real Chromium validation">/workspace/qa/src/db86ca0b4e82515795ccc1c5e32a55579582c0fe/addons/capture/tests/test_official.py:236: Use --capture-browser for real Chromium validation</skipped></testcase><testcase classname="addons.capture.tests.test_official_proof" name="test_independently_expected_settings_and_source_are_both_checked[False]" file="addons/capture/tests/test_official_proof.py" line="45" time="0.170" /><testcase classname="addons.capture.tests.test_official_proof" name="test_independently_expected_settings_and_source_are_both_checked[True]" file="addons/capture/tests/test_official_proof.py" line="45" time="0.174" /><testcase classname="addons.capture.tests.test_official_proof" name="test_approved_workflow_and_fresh_context_required[False]" file="addons/capture/tests/test_official_proof.py" line="66" time="0.178" /><testcase classname="addons.capture.tests.test_official_proof" name="test_approved_workflow_and_fresh_context_required[True]" file="addons/capture/tests/test_official_proof.py" line="66" time="0.186" /><testcase classname="addons.capture.tests.test_official_proof" name="test_missing_reordered_or_duplicate_video_segments_rejected[segments0]" file="addons/capture/tests/test_official_proof.py" line="95" time="0.129" /><testcase classname="addons.capture.tests.test_official_proof" name="test_missing_reordered_or_duplicate_video_segments_rejected[segments1]" file="addons/capture/tests/test_official_proof.py" line="95" time="0.143" /><testcase classname="addons.capture.tests.test_official_proof" name="test_missing_reordered_or_duplicate_video_segments_rejected[segments2]" file="addons/capture/tests/test_official_proof.py" line="95" time="0.135" /><testcase classname="addons.capture.tests.test_official_proof" name="test_sealed_client_never_reuses_a_profile_or_starts_automatically[False]" file="addons/capture/tests/test_official_proof.py" line="105" time="1.092" /><testcase classname="addons.capture.tests.test_official_proof" name="test_sealed_client_never_reuses_a_profile_or_starts_automatically[True]" file="addons/capture/tests/test_official_proof.py" line="105" time="1.102" /><testcase classname="addons.capture.tests.test_official_proof" name="test_sealed_network_cannot_misrepresent_direct_as_proxy[False]" file="addons/capture/tests/test_official_proof.py" line="123" time="0.156" /><testcase classname="addons.capture.tests.test_official_proof" name="test_sealed_network_cannot_misrepresent_direct_as_proxy[True]" file="addons/capture/tests/test_official_proof.py" line="123" time="0.161" /><testcase classname="addons.capture.tests.test_official_proof" name="test_direct_opened_without_recording_remains_explicit_and_incomplete" file="addons/capture/tests/test_official_proof.py" line="137" time="0.000" /><testcase classname="addons.capture.tests.test_official_proof" name="test_hosted_network_is_explicit_and_proxy_secrets_stay_out_of_direct[False]" file="addons/capture/tests/test_official_proof.py" line="144" time="0.013" /><testcase classname="addons.capture.tests.test_official_proof" name="test_hosted_network_is_explicit_and_proxy_secrets_stay_out_of_direct[True]" file="addons/capture/tests/test_official_proof.py" line="144" time="0.003" /><testcase classname="addons.capture.tests.test_trusted" name="test_message_id_scope_and_bounded_gaps[public_supergroup-True]" file="addons/capture/tests/test_trusted.py" line="130" time="0.001" /><testcase classname="addons.capture.tests.test_trusted" name="test_message_id_scope_and_bounded_gaps[private_channel-True]" file="addons/capture/tests/test_trusted.py" line="130" time="0.001" /><testcase classname="addons.capture.tests.test_trusted" name="test_message_id_scope_and_bounded_gaps[personal_chat-False]" file="addons/capture/tests/test_trusted.py" line="130" time="0.001" /><testcase classname="addons.capture.tests.test_trusted" name="test_message_id_scope_and_bounded_gaps[private_group-False]" file="addons/capture/tests/test_trusted.py" line="130" time="0.001" /><testcase classname="addons.capture.tests.test_trusted" name="test_message_id_scope_and_bounded_gaps[saved_messages-False]" file="addons/capture/tests/test_trusted.py" line="130" time="0.000" /><testcase classname="addons.capture.tests.test_trusted" name="test_reply_outside_export_and_rendered_text_are_not_deletion_or_markup" file="addons/capture/tests/test_trusted.py" line="141" time="0.000" /><testcase classname="addons.capture.tests.test_trusted" name="test_reply_to_another_chat_is_not_a_local_reply_or_missing_message" file="addons/capture/tests/test_trusted.py" line="151" time="0.000" /><testcase classname="addons.capture.tests.test_trusted" name="test_reply_naming_the_exported_chat_stays_local" file="addons/capture/tests/test_trusted.py" line="167" time="0.000" /><testcase classname="addons.capture.tests.test_trusted" name="test_rich_message_text_is_compared_and_escaped" file="addons/capture/tests/test_trusted.py" line="188" time="0.000" /><testcase classname="addons.capture.tests.test_trusted" name="test_deeply_nested_rich_message_is_bounded" file="addons/capture/tests/test_trusted.py" line="201" time="0.004" /><testcase classname="addons.capture.tests.test_trusted" name="test_malformed_exports_rejected[{}]" file="addons/capture/tests/test_trusted.py" line="211" time="0.000" /><testcase classname="addons.capture.tests.test_trusted" name="test_malformed_exports_rejected[{&quot;id&quot;:1,&quot;id&quot;:2}]" file="addons/capture/tests/test_trusted.py" line="211" time="0.000" /><testcase classname="addons.capture.tests.test_trusted" name="test_malformed_exports_rejected[raw2]" file="addons/capture/tests/test_trusted.py" line="211" time="0.000" /><testcase classname="addons.capture.tests.test_trusted" name="test_malformed_exports_rejected[raw3]" file="addons/capture/tests/test_trusted.py" line="211" time="0.000" /><testcase classname="addons.capture.tests.test_trusted" name="test_malformed_exports_rejected[{&quot;x&quot;:NaN}]" file="addons/capture/tests/test_trusted.py" line="211" time="0.000" /><testcase classname="addons.capture.tests.test_trusted" name="test_malformed_exports_rejected[raw5]" file="addons/capture/tests/test_trusted.py" line="211" time="0.000" /><testcase classname="addons.capture.tests.test_trusted" name="test_visual_comparison_does_not_infer_absence_from_unseen_viewports" file="addons/capture/tests/test_trusted.py" line="218" time="0.000" /><testcase classname="addons.capture.tests.test_trusted" name="test_invalid_choices[changes0]" file="addons/capture/tests/test_trusted.py" line="227" time="0.000" /><testcase classname="addons.capture.tests.test_trusted" name="test_invalid_choices[changes1]" file="addons/capture/tests/test_trusted.py" line="227" time="0.000" /><testcase classname="addons.capture.tests.test_trusted" name="test_invalid_choices[changes2]" file="addons/capture/tests/test_trusted.py" line="227" time="0.000" /><testcase classname="addons.capture.tests.test_trusted" name="test_invalid_choices[changes3]" file="addons/capture/tests/test_trusted.py" line="227" time="0.000" /><testcase classname="addons.capture.tests.test_trusted" name="test_invalid_choices[changes4]" file="addons/capture/tests/test_trusted.py" line="227" time="0.000" /><testcase classname="addons.capture.tests.test_trusted" name="test_connector_rejects_unsafe_or_ambiguous_configuration[changes0]" file="addons/capture/tests/test_trusted.py" line="234" time="0.000" /><testcase classname="addons.capture.tests.test_trusted" name="test_connector_rejects_unsafe_or_ambiguous_configuration[changes1]" file="addons/capture/tests/test_trusted.py" line="234" time="0.000" /><testcase classname="addons.capture.tests.test_trusted" name="test_connector_rejects_unsafe_or_ambiguous_configuration[changes2]" file="addons/capture/tests/test_trusted.py" line="234" time="0.000" /><testcase classname="addons.capture.tests.test_trusted" name="test_connector_rejects_unsafe_or_ambiguous_configuration[changes3]" file="addons/capture/tests/test_trusted.py" line="234" time="0.000" /><testcase classname="addons.capture.tests.test_trusted" name="test_connector_rejects_unsafe_or_ambiguous_configuration[changes4]" file="addons/capture/tests/test_trusted.py" line="234" time="0.000" /><testcase classname="addons.capture.tests.test_trusted" name="test_connector_rejects_unsafe_or_ambiguous_configuration[changes5]" file="addons/capture/tests/test_trusted.py" line="234" time="0.000" /><testcase classname="addons.capture.tests.test_trusted" name="test_auth_origin_stream_limit_and_witness_read_only" file="addons/capture/tests/test_trusted.py" line="241" time="0.601" /><testcase classname="addons.capture.tests.test_trusted" name="test_setup_secrets_not_recorded_and_capture_input_guard" file="addons/capture/tests/test_trusted.py" line="254" time="0.614" /><testcase classname="addons.capture.tests.test_trusted" name="test_unmapped_client_window_can_retry_setup_but_stops_collection" file="addons/capture/tests/test_trusted.py" line="271" time="0.600" /><testcase classname="addons.capture.tests.test_trusted" name="test_route_or_focus_loss_stops_client[bad_route]" file="addons/capture/tests/test_trusted.py" line="290" time="0.597" /><testcase classname="addons.capture.tests.test_trusted" name="test_route_or_focus_loss_stops_client[bad_focus]" file="addons/capture/tests/test_trusted.py" line="290" time="0.600" /><testcase classname="addons.capture.tests.test_trusted" name="test_original_export_report_annotation_cleanup_and_offline_verification" file="addons/capture/tests/test_trusted.py" line="300" time="0.593" /><testcase classname="addons.capture.tests.test_trusted" name="test_import_cannot_read_outside_inbox_or_switch_chat" file="addons/capture/tests/test_trusted.py" line="338" time="0.596" /><testcase classname="addons.capture.tests.test_trusted" name="test_signed_but_wrong_analysis_is_rejected" file="addons/capture/tests/test_trusted.py" line="351" time="0.597" /><testcase classname="addons.capture.tests.test_trusted" name="test_earlier_analysis_format_verifies_and_unknown_format_is_rejected" file="addons/capture/tests/test_trusted.py" line="366" time="0.593" /><testcase classname="addons.capture.tests.test_trusted" name="test_network_guard_drops_ipv6_dns_and_direct_egress" file="addons/capture/tests/test_trusted.py" line="386" time="0.002" /><testcase classname="addons.capture.tests.test_trusted" name="test_public_source_includes_complete_trusted_runtime" file="addons/capture/tests/test_trusted.py" line="399" time="0.209" /><testcase classname="addons.capture.tests.test_trusted" name="test_restart_archives_case_and_cannot_mix_accounts" file="addons/capture/tests/test_trusted.py" line="409" time="1.151" /><testcase classname="addons.capture.tests.test_trusted" name="test_kill_switch_stops_process_before_waiting_for_frame_lock" file="addons/capture/tests/test_trusted.py" line="423" time="0.595" /><testcase classname="addons.capture.tests.test_trusted" name="test_real_ffmpeg_video_segments_and_verified_trusted_bundle" file="addons/capture/tests/test_trusted.py" line="446" time="2.403" /><testcase classname="addons.capture.tests.test_trusted" name="test_trusted_panel_real_browser_flow_and_mobile_layout" file="addons/capture/tests/test_trusted.py" line="475" time="0.001"><skipped type="pytest.skip" message="Use --capture-browser for the real Chromium acceptance test">/workspace/qa/src/db86ca0b4e82515795ccc1c5e32a55579582c0fe/addons/capture/tests/test_trusted.py:478: Use --capture-browser for the real Chromium acceptance test</skipped></testcase><testcase classname="addons.capture.tests.test_trusted_anchors" name="test_drand_two_relays_and_no_false_time_bound" file="addons/capture/tests/test_trusted_anchors.py" line="17" time="0.000" /><testcase classname="addons.capture.tests.test_trusted_anchors" name="test_drand_mismatch_stale_and_bad_digest_fail" file="addons/capture/tests/test_trusted_anchors.py" line="32" time="0.000" /><testcase classname="addons.capture.tests.test_trusted_anchors" name="test_cloudflare_queries_are_read_only_scoped_and_token_is_not_exported" file="addons/capture/tests/test_trusted_anchors.py" line="42" time="0.079"><failure message="AssertionError: assert 'no proof of continuous presence' in 'provider state sampled at the polled time'">tmp_path = PosixPath('/tmp/pytest-of-root/pytest-6/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
&gt;           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</failure></testcase><testcase classname="addons.capture.tests.test_trusted_anchors" name="test_provider_denials_are_unavailable_not_healthy" file="addons/capture/tests/test_trusted_anchors.py" line="66" time="0.056" /><testcase classname="addons.capture.tests.test_trusted_anchors" name="test_egress_change_or_warp_loss_fails_closed" file="addons/capture/tests/test_trusted_anchors.py" line="78" time="0.002" /></testsuite></testsuites>