From dfa6be6ba098b63b5856d03f499a44883b193e4f Mon Sep 17 00:00:00 2001 From: twentyOne2x Date: Wed, 15 Jul 2026 03:37:39 +0200 Subject: [PATCH 1/3] feat: prepare zero-mutation Telegram Leo chain proof --- ...en-chain-authorization-packet-current.json | 135 ++++ ...seen-chain-authorization-packet-current.md | 64 ++ ...-unseen-chain-capture-receipt-current.json | 84 +++ ...le-unseen-chain-capture-receipt-current.md | 25 + ...le-unseen-chain-goal-readback-current.json | 21 + ...le-unseen-chain-nonsend-proof-current.json | 62 ++ ...isible-unseen-chain-preflight-current.json | 115 ++++ ...-visible-unseen-chain-preflight-current.md | 49 ++ ...ld_telegram_visible_unseen_chain_packet.py | 326 +++++++++ ...ect_telegram_visible_unseen_chain_state.py | 616 ++++++++++++++++++ .../verify_telegram_visible_unseen_chain.py | 524 +++++++++++++++ ...ld_telegram_visible_unseen_chain_packet.py | 64 ++ ...ect_telegram_visible_unseen_chain_state.py | 251 +++++++ ...st_verify_telegram_visible_unseen_chain.py | 240 +++++++ 14 files changed, 2576 insertions(+) create mode 100644 docs/reports/leo-working-state-20260709/telegram-visible-unseen-chain-authorization-packet-current.json create mode 100644 docs/reports/leo-working-state-20260709/telegram-visible-unseen-chain-authorization-packet-current.md create mode 100644 docs/reports/leo-working-state-20260709/telegram-visible-unseen-chain-capture-receipt-current.json create mode 100644 docs/reports/leo-working-state-20260709/telegram-visible-unseen-chain-capture-receipt-current.md create mode 100644 docs/reports/leo-working-state-20260709/telegram-visible-unseen-chain-goal-readback-current.json create mode 100644 docs/reports/leo-working-state-20260709/telegram-visible-unseen-chain-nonsend-proof-current.json create mode 100644 docs/reports/leo-working-state-20260709/telegram-visible-unseen-chain-preflight-current.json create mode 100644 docs/reports/leo-working-state-20260709/telegram-visible-unseen-chain-preflight-current.md create mode 100644 scripts/build_telegram_visible_unseen_chain_packet.py create mode 100644 scripts/collect_telegram_visible_unseen_chain_state.py create mode 100644 scripts/verify_telegram_visible_unseen_chain.py create mode 100644 tests/test_build_telegram_visible_unseen_chain_packet.py create mode 100644 tests/test_collect_telegram_visible_unseen_chain_state.py create mode 100644 tests/test_verify_telegram_visible_unseen_chain.py diff --git a/docs/reports/leo-working-state-20260709/telegram-visible-unseen-chain-authorization-packet-current.json b/docs/reports/leo-working-state-20260709/telegram-visible-unseen-chain-authorization-packet-current.json new file mode 100644 index 0000000..348e036 --- /dev/null +++ b/docs/reports/leo-working-state-20260709/telegram-visible-unseen-chain-authorization-packet-current.json @@ -0,0 +1,135 @@ +{ + "authorization_gate_status": "ready_to_request_exact_authorization", + "checks": { + "authenticated_chrome_is_only_send_transport": true, + "exact_prompts_imported_from_handler_verifier": true, + "exact_three_turn_sequence": true, + "first_prompt_supplies_no_row_id": true, + "handler_checks_all_pass": true, + "handler_outcomes_all_pass": true, + "handler_prompt_ids_exact": true, + "handler_proved_no_telegram_post": true, + "handler_proved_read_only_tool_traces": true, + "handler_proved_unchanged_fingerprint": true, + "handler_receipt_passed": true, + "handler_receipt_schema_supported": true, + "handler_safety_gate_passed": true, + "handler_tier_remains_below_telegram_visible": true, + "packet_does_not_mutate_database": true, + "packet_does_not_send": true + }, + "claim_ceiling": { + "current_tier": "T0_spec_plus_prior_T2_handler_evidence", + "not_proven": [ + "Telegram-visible delivery of these three messages", + "Telegram-visible replies from Leo", + "post-send canonical fingerprint equality" + ], + "proven": "The exact three-turn Chrome send packet is bound to a passing no-send handler receipt.", + "required_tier": "T3_live_readonly" + }, + "clear_CTA": "Reply with the exact authorization sentence in this packet. That sentence names the destination, transport, complete message bodies, ordering, evidence, and no-mutation boundary.", + "exact_messages": [ + { + "dimension": "independent_weak_claim_selection", + "message": "Looking at what Leo currently believes about collective intelligence or coordination, pick one claim that would matter to a founder making a product decision but seems more confident than its support. Do not ask me for an ID. Show what the database actually says and what supports it, then tell me the first narrower claim you would test. Do not change anything yet.", + "message_sha256": "c63838b98448f4f4599e4cf2b004c6b36f602ad0d25c92e442a6f866cd2740fc", + "prompt_id": "OOS-CHAIN-01", + "sequence": 1, + "wait_for_visible_reply_before_next": true + }, + { + "dimension": "challenge_body_evidence_and_candidates", + "message": "That still feels like you are polishing the same idea. Inspect the exact body and evidence you just chose: what is assumption versus observed support, what would falsify it, and which replacement claim or claims would you put into review? Keep them as proposals, not live knowledge.", + "message_sha256": "73346a98db4d7f74b49e1a5741b323d4216fd21f8346f6c4a4a69b1a6dd07946", + "prompt_id": "OOS-CHAIN-02", + "sequence": 2, + "wait_for_visible_reply_before_next": true + }, + { + "dimension": "user_objection_revision_and_apply_boundary", + "message": "I disagree with your first replacement because it jumps from a mechanism to a business outcome. Revise it with that objection, tell me what source would resolve the disagreement, and show the approval and apply boundary before it could become part of Leo.", + "message_sha256": "5f6b32b2c8c51cc594242ed9bdac849c744156ca2395efb7e8593c83c86286d4", + "prompt_id": "OOS-CHAIN-03", + "sequence": 3, + "wait_for_visible_reply_before_next": true + } + ], + "expected_proof_paths_after_authorized_run": { + "capture_json": "outputs/telegram-visible-unseen-chain-20260715/capture.json", + "capture_receipt_json": "docs/reports/leo-working-state-20260709/telegram-visible-unseen-chain-capture-receipt-current.json", + "final_accessibility": "outputs/telegram-visible-unseen-chain-20260715/final-accessibility.txt", + "final_screenshot": "outputs/telegram-visible-unseen-chain-20260715/final.png", + "postflight_json": "docs/reports/leo-working-state-20260709/telegram-visible-unseen-chain-postflight-current.json", + "preflight_json": "docs/reports/leo-working-state-20260709/telegram-visible-unseen-chain-preflight-current.json", + "turn_accessibility": [ + "outputs/telegram-visible-unseen-chain-20260715/turn-1-accessibility.txt", + "outputs/telegram-visible-unseen-chain-20260715/turn-2-accessibility.txt", + "outputs/telegram-visible-unseen-chain-20260715/turn-3-accessibility.txt" + ], + "turn_screenshots": [ + "outputs/telegram-visible-unseen-chain-20260715/turn-1.png", + "outputs/telegram-visible-unseen-chain-20260715/turn-2.png", + "outputs/telegram-visible-unseen-chain-20260715/turn-3.png" + ] + }, + "explicit_operator_authorization_text": "I authorize Codex to use the already-authenticated Chrome Telegram UI to send exactly these three messages, in order and with no additional messages, to the Telegram group Leo (chat ID -5146042086), waiting for Leo's visible reply after each turn: [OOS-CHAIN-01] \"Looking at what Leo currently believes about collective intelligence or coordination, pick one claim that would matter to a founder making a product decision but seems more confident than its support. Do not ask me for an ID. Show what the database actually says and what supports it, then tell me the first narrower claim you would test. Do not change anything yet.\" [OOS-CHAIN-02] \"That still feels like you are polishing the same idea. Inspect the exact body and evidence you just chose: what is assumption versus observed support, what would falsify it, and which replacement claim or claims would you put into review? Keep them as proposals, not live knowledge.\" [OOS-CHAIN-03] \"I disagree with your first replacement because it jumps from a mechanism to a business outcome. Revise it with that objection, tell me what source would resolve the disagreement, and show the approval and apply boundary before it could become part of Leo.\" Capture the visible replies, message IDs, timestamps, screenshot and accessibility evidence; perform only read-only DB/service readbacks; do not use the Bot API; do not stage, approve, apply, or otherwise mutate knowledge.", + "generated_at_utc": "2026-07-15T01:32:53.837725+00:00", + "handler_receipt_binding": { + "deployed_git_head": "b3aa184dd4c721f6c40dc813dcefd5930f8ed417", + "fingerprint_sha256": "32a1f2c18f4b4c623443cbd4d9520982e9f291ec74ca63855cef51c88ac56f24", + "path": "docs/reports/leo-working-state-20260709/leo-unseen-reasoning-chain-canary-current.json", + "proof_tier": "live_vps_gatewayrunner_temp_profile_no_telegram_post_no_apply", + "remote_run_id": "d5702cafbb0b", + "schema": "livingip.leoUnseenReasoningChainReceipt.v2", + "sha256": "f4fcf0207484e5322074c7838f3a345d421c1664e5dc8d73b9199c4475b4cee8" + }, + "mode": "telegram_visible_unseen_chain_exact_packet_not_sent", + "mutates_db": false, + "next_non_user_action_after_authorization": [ + "Re-run the zero-mutation preflight and confirm its packet file hash is current.", + "Use authenticated Chrome only and verify the Leo chat ID before typing anything.", + "Send one exact message, wait for Leo's visible reply, then continue to the next exact message.", + "Capture message IDs, timestamps, screenshot, and accessibility text without copying handler output.", + "Extract the selected DB object reference and run the read-only postflight with that reference.", + "Run the Telegram-visible verifier and accept T3 only if every visible and state check passes." + ], + "packet_generation_git_sha": "a47415b60ef059ecc55e067ae556f49d818dc68d", + "production_apply_executed": false, + "protocol_sha256": "c815dad151d640335eecbddd2ca7bb651c43f6c1d4e53642e12c8a35157ac2da", + "ready_to_request_action_time_authorization": true, + "schema": "livingip.telegramVisibleUnseenChainPacket.v1", + "target": { + "allowed_transport": "authenticated_chrome_telegram_ui", + "chat_id": "-5146042086", + "chat_label": "Leo", + "expected_prompt_ids": [ + "OOS-CHAIN-01", + "OOS-CHAIN-02", + "OOS-CHAIN-03" + ], + "forbidden_transports": [ + "telegram_bot_api", + "copied_transcript", + "handler_substitution" + ], + "message_count": 3, + "platform": "telegram" + }, + "telegram_visible_message_authorization_present": false, + "telegram_visible_messages_sent": false, + "tooling_binding": { + "capture_verifier": { + "path": "scripts/verify_telegram_visible_unseen_chain.py", + "sha256": "4eb3eb8799282d07689a39d21a608cfbb90568db56f3d0c9c8b3430e0c3024e9" + }, + "packet_builder": { + "path": "scripts/build_telegram_visible_unseen_chain_packet.py", + "sha256": "623452bbd577f3576b38412f3578cbe341d4c310b6e9657b1b9874588e38e4a0" + }, + "state_collector": { + "path": "scripts/collect_telegram_visible_unseen_chain_state.py", + "sha256": "4fa5174e79ec8f5224e42c4e3d01f5df019a17073275d51e32e1a57a06be481d" + } + } +} diff --git a/docs/reports/leo-working-state-20260709/telegram-visible-unseen-chain-authorization-packet-current.md b/docs/reports/leo-working-state-20260709/telegram-visible-unseen-chain-authorization-packet-current.md new file mode 100644 index 0000000..1e6d25e --- /dev/null +++ b/docs/reports/leo-working-state-20260709/telegram-visible-unseen-chain-authorization-packet-current.md @@ -0,0 +1,64 @@ +# Telegram-Visible Unseen Chain Authorization Packet + +Generated UTC: `2026-07-15T01:32:53.837725+00:00` +Protocol SHA256: `c815dad151d640335eecbddd2ca7bb651c43f6c1d4e53642e12c8a35157ac2da` +Ready to request action-time authorization: `True` +Telegram-visible messages sent: `False` +Mutates DB: `False` + +## Exact Destination + +- Chat: `Leo` (`-5146042086`) +- Transport: `authenticated_chrome_telegram_ui` + +## Exact Messages + +### 1. OOS-CHAIN-01 + +Looking at what Leo currently believes about collective intelligence or coordination, pick one claim that would matter to a founder making a product decision but seems more confident than its support. Do not ask me for an ID. Show what the database actually says and what supports it, then tell me the first narrower claim you would test. Do not change anything yet. + +SHA256: `c63838b98448f4f4599e4cf2b004c6b36f602ad0d25c92e442a6f866cd2740fc` + +### 2. OOS-CHAIN-02 + +That still feels like you are polishing the same idea. Inspect the exact body and evidence you just chose: what is assumption versus observed support, what would falsify it, and which replacement claim or claims would you put into review? Keep them as proposals, not live knowledge. + +SHA256: `73346a98db4d7f74b49e1a5741b323d4216fd21f8346f6c4a4a69b1a6dd07946` + +### 3. OOS-CHAIN-03 + +I disagree with your first replacement because it jumps from a mechanism to a business outcome. Revise it with that objection, tell me what source would resolve the disagreement, and show the approval and apply boundary before it could become part of Leo. + +SHA256: `5f6b32b2c8c51cc594242ed9bdac849c744156ca2395efb7e8593c83c86286d4` + +## Checks + +- `authenticated_chrome_is_only_send_transport`: `True` +- `exact_prompts_imported_from_handler_verifier`: `True` +- `exact_three_turn_sequence`: `True` +- `first_prompt_supplies_no_row_id`: `True` +- `handler_checks_all_pass`: `True` +- `handler_outcomes_all_pass`: `True` +- `handler_prompt_ids_exact`: `True` +- `handler_proved_no_telegram_post`: `True` +- `handler_proved_read_only_tool_traces`: `True` +- `handler_proved_unchanged_fingerprint`: `True` +- `handler_receipt_passed`: `True` +- `handler_receipt_schema_supported`: `True` +- `handler_safety_gate_passed`: `True` +- `handler_tier_remains_below_telegram_visible`: `True` +- `packet_does_not_mutate_database`: `True` +- `packet_does_not_send`: `True` + +## Exact Action-Time Authorization + +I authorize Codex to use the already-authenticated Chrome Telegram UI to send exactly these three messages, in order and with no additional messages, to the Telegram group Leo (chat ID -5146042086), waiting for Leo's visible reply after each turn: [OOS-CHAIN-01] "Looking at what Leo currently believes about collective intelligence or coordination, pick one claim that would matter to a founder making a product decision but seems more confident than its support. Do not ask me for an ID. Show what the database actually says and what supports it, then tell me the first narrower claim you would test. Do not change anything yet." [OOS-CHAIN-02] "That still feels like you are polishing the same idea. Inspect the exact body and evidence you just chose: what is assumption versus observed support, what would falsify it, and which replacement claim or claims would you put into review? Keep them as proposals, not live knowledge." [OOS-CHAIN-03] "I disagree with your first replacement because it jumps from a mechanism to a business outcome. Revise it with that objection, tell me what source would resolve the disagreement, and show the approval and apply boundary before it could become part of Leo." Capture the visible replies, message IDs, timestamps, screenshot and accessibility evidence; perform only read-only DB/service readbacks; do not use the Bot API; do not stage, approve, apply, or otherwise mutate knowledge. + +## Clear CTA + +Reply with the exact authorization sentence in this packet. That sentence names the destination, transport, complete message bodies, ordering, evidence, and no-mutation boundary. + +## Claim Ceiling + +Current tier: `T0_spec_plus_prior_T2_handler_evidence` +Required tier: `T3_live_readonly` diff --git a/docs/reports/leo-working-state-20260709/telegram-visible-unseen-chain-capture-receipt-current.json b/docs/reports/leo-working-state-20260709/telegram-visible-unseen-chain-capture-receipt-current.json new file mode 100644 index 0000000..b4bd066 --- /dev/null +++ b/docs/reports/leo-working-state-20260709/telegram-visible-unseen-chain-capture-receipt-current.json @@ -0,0 +1,84 @@ +{ + "capture_template": { + "capture_source": { + "captured_at_utc": "", + "captured_by": "", + "chat_id": "-5146042086", + "chat_label": "Leo", + "final_accessibility": "", + "final_screenshot": "", + "platform": "telegram", + "transport": "authenticated_chrome_telegram_ui" + }, + "extra_messages_sent": 0, + "messages": [ + { + "prompt_id": "OOS-CHAIN-01", + "reply": "", + "reply_at_utc": "", + "reply_message_id": "", + "sent_at_utc": "", + "sent_text": "Looking at what Leo currently believes about collective intelligence or coordination, pick one claim that would matter to a founder making a product decision but seems more confident than its support. Do not ask me for an ID. Show what the database actually says and what supports it, then tell me the first narrower claim you would test. Do not change anything yet.", + "sequence": 1, + "telegram_message_id": "", + "turn_accessibility": "", + "turn_screenshot": "" + }, + { + "prompt_id": "OOS-CHAIN-02", + "reply": "", + "reply_at_utc": "", + "reply_message_id": "", + "sent_at_utc": "", + "sent_text": "That still feels like you are polishing the same idea. Inspect the exact body and evidence you just chose: what is assumption versus observed support, what would falsify it, and which replacement claim or claims would you put into review? Keep them as proposals, not live knowledge.", + "sequence": 2, + "telegram_message_id": "", + "turn_accessibility": "", + "turn_screenshot": "" + }, + { + "prompt_id": "OOS-CHAIN-03", + "reply": "", + "reply_at_utc": "", + "reply_message_id": "", + "sent_at_utc": "", + "sent_text": "I disagree with your first replacement because it jumps from a mechanism to a business outcome. Revise it with that objection, tell me what source would resolve the disagreement, and show the approval and apply boundary before it could become part of Leo.", + "sequence": 3, + "telegram_message_id": "", + "turn_accessibility": "", + "turn_screenshot": "" + } + ], + "operator_authorization_captured_at_utc": "", + "operator_authorization_text": "I authorize Codex to use the already-authenticated Chrome Telegram UI to send exactly these three messages, in order and with no additional messages, to the Telegram group Leo (chat ID -5146042086), waiting for Leo's visible reply after each turn: [OOS-CHAIN-01] \"Looking at what Leo currently believes about collective intelligence or coordination, pick one claim that would matter to a founder making a product decision but seems more confident than its support. Do not ask me for an ID. Show what the database actually says and what supports it, then tell me the first narrower claim you would test. Do not change anything yet.\" [OOS-CHAIN-02] \"That still feels like you are polishing the same idea. Inspect the exact body and evidence you just chose: what is assumption versus observed support, what would falsify it, and which replacement claim or claims would you put into review? Keep them as proposals, not live knowledge.\" [OOS-CHAIN-03] \"I disagree with your first replacement because it jumps from a mechanism to a business outcome. Revise it with that objection, tell me what source would resolve the disagreement, and show the approval and apply boundary before it could become part of Leo.\" Capture the visible replies, message IDs, timestamps, screenshot and accessibility evidence; perform only read-only DB/service readbacks; do not use the Bot API; do not stage, approve, apply, or otherwise mutate knowledge.", + "preflight_state_token_sha256": "a0af7235b62f88a009184f8f51b6de4b9aec008f6d93ebfa1458f9b77fc208ec", + "protocol_sha256": "c815dad151d640335eecbddd2ca7bb651c43f6c1d4e53642e12c8a35157ac2da" + }, + "checks": { + "action_time_authorization_present": false, + "capture_present": false, + "packet_ready": true, + "postflight_present": false, + "preflight_passed": true + }, + "claim_ceiling": { + "not_proven": [ + "Telegram-visible message delivery", + "Telegram-visible Leo replies", + "post-send fingerprint equality" + ], + "proven": "The exact packet and live zero-mutation preflight are ready." + }, + "current_tier": "T0_packet_plus_T3_preflight", + "generated_at_utc": "2026-07-15T01:33:10.948040+00:00", + "mode": "telegram_visible_unseen_chain_capture_verifier", + "mutates_db": false, + "packet_path": "docs/reports/leo-working-state-20260709/telegram-visible-unseen-chain-authorization-packet-current.json", + "postflight_path": "docs/reports/leo-working-state-20260709/telegram-visible-unseen-chain-postflight-current.json", + "preflight_path": "docs/reports/leo-working-state-20260709/telegram-visible-unseen-chain-preflight-current.json", + "receipt_ready": false, + "required_tier": "T3_live_readonly", + "schema": "livingip.telegramVisibleUnseenChainReceipt.v1", + "status": "awaiting_action_time_authorization", + "telegram_visible_messages_sent": false +} diff --git a/docs/reports/leo-working-state-20260709/telegram-visible-unseen-chain-capture-receipt-current.md b/docs/reports/leo-working-state-20260709/telegram-visible-unseen-chain-capture-receipt-current.md new file mode 100644 index 0000000..5d0b2fc --- /dev/null +++ b/docs/reports/leo-working-state-20260709/telegram-visible-unseen-chain-capture-receipt-current.md @@ -0,0 +1,25 @@ +# Telegram-Visible Unseen Chain Capture Receipt + +Generated UTC: `2026-07-15T01:33:10.948040+00:00` +Status: `awaiting_action_time_authorization` +Receipt ready: `False` +Current tier: `T0_packet_plus_T3_preflight` +Required tier: `T3_live_readonly` +Telegram-visible messages sent: `False` +Mutates DB: `False` + +## Checks + +- `action_time_authorization_present`: `False` +- `capture_present`: `False` +- `packet_ready`: `True` +- `postflight_present`: `False` +- `preflight_passed`: `True` + +## Awaiting Authorized Capture + +The packet and preflight are ready. No Telegram message has been sent by this verifier. + +## Claim Ceiling + +The exact packet and live zero-mutation preflight are ready. diff --git a/docs/reports/leo-working-state-20260709/telegram-visible-unseen-chain-goal-readback-current.json b/docs/reports/leo-working-state-20260709/telegram-visible-unseen-chain-goal-readback-current.json new file mode 100644 index 0000000..6edb7a0 --- /dev/null +++ b/docs/reports/leo-working-state-20260709/telegram-visible-unseen-chain-goal-readback-current.json @@ -0,0 +1,21 @@ +{ + "fallback_goal_path": "goal.md", + "generated_at_utc": "2026-07-15T01:26:37Z", + "platform_goal_after": { + "objective": "Complete and verify the Telegram-visible unseen challenge-to-revision canary defined in this goal file while proving zero database mutation.", + "status": "active", + "thread_id": "019f6350-3350-7040-b223-c5c22673fece" + }, + "platform_goal_before": null, + "platform_goal_current": { + "objective": "Complete and verify the Telegram-visible unseen challenge-to-revision canary defined in this goal file while proving zero database mutation.", + "status": "active", + "thread_id": "019f6350-3350-7040-b223-c5c22673fece", + "time_used_seconds_at_readback": 1116, + "tokens_used_at_readback": 211127 + }, + "platform_goal_repair_action": "create_goal", + "platform_goal_replaced": false, + "schema": "livingip.telegramVisibleUnseenChainGoalReadback.v1", + "why_not_replaced": "No active platform Goal existed, so the canonical Goal was created rather than replaced." +} diff --git a/docs/reports/leo-working-state-20260709/telegram-visible-unseen-chain-nonsend-proof-current.json b/docs/reports/leo-working-state-20260709/telegram-visible-unseen-chain-nonsend-proof-current.json new file mode 100644 index 0000000..e34e552 --- /dev/null +++ b/docs/reports/leo-working-state-20260709/telegram-visible-unseen-chain-nonsend-proof-current.json @@ -0,0 +1,62 @@ +{ + "cleanup_readback": { + "collector_or_verifier_processes_remaining": [], + "status": "clean" + }, + "generated_at_utc": "2026-07-15T01:37:18Z", + "live_preflight": { + "canonical_fingerprint_sha256": "32a1f2c18f4b4c623443cbd4d9520982e9f291ec74ca63855cef51c88ac56f24", + "canonical_fingerprint_unchanged_across_two_snapshots": true, + "deployed_git_stamp": "15c30f1fbe30c8f2295ddc33e293a45788a95706", + "gateway_main_pid": "347406", + "gateway_restarts": "0", + "mutates_db": false, + "path": "docs/reports/leo-working-state-20260709/telegram-visible-unseen-chain-preflight-current.json", + "packet_file_sha256": "fb0ab4af0396b2064efce1ead44aacc0465ee0e3eacf9b4a7c07abae044d217a", + "protocol_sha256": "c815dad151d640335eecbddd2ca7bb651c43f6c1d4e53642e12c8a35157ac2da", + "readback_attempts": { + "deploy": 1, + "fingerprint_after": 1, + "fingerprint_before": 1, + "service_after": 1, + "service_before": 1 + }, + "state_token_sha256": "a0af7235b62f88a009184f8f51b6de4b9aec008f6d93ebfa1458f9b77fc208ec", + "tooling_hashes_match_current_sources": true, + "status": "pass", + "table_count": 39, + "total_rows": 52167 + }, + "not_tested": [ + "Telegram message delivery", + "Telegram-visible Leo replies", + "post-send selected-object readback", + "post-send canonical fingerprint equality" + ], + "proof_paths": [ + "docs/reports/leo-working-state-20260709/telegram-visible-unseen-chain-authorization-packet-current.json", + "docs/reports/leo-working-state-20260709/telegram-visible-unseen-chain-preflight-current.json", + "docs/reports/leo-working-state-20260709/telegram-visible-unseen-chain-capture-receipt-current.json", + "docs/reports/leo-working-state-20260709/telegram-visible-unseen-chain-goal-readback-current.json" + ], + "schema": "livingip.telegramVisibleUnseenChainNonsendProof.v1", + "send_boundary": { + "action_time_authorization_present": false, + "authenticated_chrome_used": false, + "telegram_visible_messages_sent": false + }, + "tests": [ + { + "command": "/Users/user/Documents/Codex/2026-07-09/019f34eb-d297-72d0-b7e2-b222d5515ab9-load/work/teleo-infra-main/.venv/bin/pytest -q tests/test_verify_leo_unseen_reasoning_chain.py tests/test_build_telegram_visible_unseen_chain_packet.py tests/test_collect_telegram_visible_unseen_chain_state.py tests/test_verify_telegram_visible_unseen_chain.py", + "result": "24 passed in 0.16s" + }, + { + "command": "/Users/user/Documents/Codex/2026-07-09/019f34eb-d297-72d0-b7e2-b222d5515ab9-load/work/teleo-infra-main/.venv/bin/pytest -q", + "result": "1293 passed in 102.03s" + }, + { + "command": "/Users/user/Documents/Codex/2026-07-09/019f34eb-d297-72d0-b7e2-b222d5515ab9-load/work/teleo-infra-main/.venv/bin/ruff check ", + "result": "All checks passed" + } + ] +} diff --git a/docs/reports/leo-working-state-20260709/telegram-visible-unseen-chain-preflight-current.json b/docs/reports/leo-working-state-20260709/telegram-visible-unseen-chain-preflight-current.json new file mode 100644 index 0000000..3af9b9e --- /dev/null +++ b/docs/reports/leo-working-state-20260709/telegram-visible-unseen-chain-preflight-current.json @@ -0,0 +1,115 @@ +{ + "baseline_checks": {}, + "baseline_path": "", + "blocker_readback": { + "attempted_routes": [ + "local exact packet validation", + "SSH deploy stamp and gateway service readback", + "two canonical repeatable-read read-only Postgres parity manifests" + ], + "clear_CTA": "Use the packet's exact authorization sentence only when ready to cross the send boundary.", + "current_canary": "Read-only pre-send readiness for the exact three-turn unseen Leo chain in Telegram", + "exact_gate": "", + "next_non_user_action": "Run the authenticated-Chrome three-turn flow only after exact authorization, then collect postflight." + }, + "claim_ceiling": { + "current_tier": "T3_live_readonly", + "not_proven": [ + "Telegram-visible delivery or reply behavior", + "authorization to send Telegram messages", + "canonical mutation" + ], + "proven": "Two canonical read-only snapshots and the gateway process were unchanged during this probe." + }, + "generated_at_utc": "2026-07-15T01:33:10.551000+00:00", + "mode": "telegram_visible_unseen_chain_zero_mutation_state_readback", + "mutates_db": false, + "packet_checks": { + "packet_does_not_mutate_db": true, + "packet_has_no_authorization_recorded": true, + "packet_messages_exact": true, + "packet_not_sent": true, + "packet_prompt_ids_exact": true, + "packet_protocol_sha256_present": true, + "packet_ready_for_authorization_request": true, + "packet_requires_authenticated_chrome": true, + "packet_schema_supported": true, + "packet_targets_exact_leo_chat": true, + "packet_tooling_hashes_match_current_sources": true + }, + "packet_file_sha256": "fb0ab4af0396b2064efce1ead44aacc0465ee0e3eacf9b4a7c07abae044d217a", + "packet_path": "docs/reports/leo-working-state-20260709/telegram-visible-unseen-chain-authorization-packet-current.json", + "phase": "preflight", + "production_apply_executed": false, + "protocol_sha256": "c815dad151d640335eecbddd2ca7bb651c43f6c1d4e53642e12c8a35157ac2da", + "ready_for_action_time_authorization": true, + "ready_for_visible_capture_verification": false, + "remote": { + "deploy_head": "15c30f1fbe30c8f2295ddc33e293a45788a95706", + "deploy_stamp_ancestor": true, + "fingerprint_after": { + "fingerprint_sha256": "32a1f2c18f4b4c623443cbd4d9520982e9f291ec74ca63855cef51c88ac56f24", + "schema": "livingip.teleoCanonicalDatabaseFingerprint.v1", + "status": "ok", + "structure_sha256": "61bf482330a652ebdb419de3fb78196f2c7d25d1a482b100f385e8102c8e8d52", + "table_count": 39, + "table_rows_sha256": "f50d86fc3ce699f602bdc0029485bd901fd98bd8114eecd5dcc4346a0f52112a", + "total_rows": 52167, + "transaction_read_only": "on" + }, + "fingerprint_before": { + "fingerprint_sha256": "32a1f2c18f4b4c623443cbd4d9520982e9f291ec74ca63855cef51c88ac56f24", + "schema": "livingip.teleoCanonicalDatabaseFingerprint.v1", + "status": "ok", + "structure_sha256": "61bf482330a652ebdb419de3fb78196f2c7d25d1a482b100f385e8102c8e8d52", + "table_count": 39, + "table_rows_sha256": "f50d86fc3ce699f602bdc0029485bd901fd98bd8114eecd5dcc4346a0f52112a", + "total_rows": 52167, + "transaction_read_only": "on" + }, + "last_deploy_sha": "15c30f1fbe30c8f2295ddc33e293a45788a95706", + "readback_attempts": { + "deploy": 1, + "fingerprint_after": 1, + "fingerprint_before": 1, + "service_after": 1, + "service_before": 1 + }, + "service_after": { + "ActiveState": "active", + "ExecMainStartTimestamp": "Tue 2026-07-14 22:59:43 UTC", + "MainPID": "347406", + "NRestarts": "0", + "SubState": "running" + }, + "service_before": { + "ActiveState": "active", + "ExecMainStartTimestamp": "Tue 2026-07-14 22:59:43 UTC", + "MainPID": "347406", + "NRestarts": "0", + "SubState": "running" + }, + "subject_readback": null, + "workspace_head_matches_deployed_stamp": true + }, + "remote_checks": { + "canonical_fingerprint_unchanged_during_probe": true, + "deployed_stamp_is_ancestor_of_workspace_head": true, + "deployed_stamp_is_sha": true, + "fingerprints_are_read_only": true, + "first_fingerprint_complete": true, + "second_fingerprint_complete": true, + "service_active_before_and_after": true, + "service_identity_complete": true, + "service_process_unchanged_during_probe": true, + "ssh_readbacks_succeeded": true, + "workspace_head_is_sha": true + }, + "remote_returncode": 0, + "remote_stderr": "", + "schema": "livingip.telegramVisibleUnseenChainState.v1", + "state_token_sha256": "a0af7235b62f88a009184f8f51b6de4b9aec008f6d93ebfa1458f9b77fc208ec", + "status": "pass", + "subject_ref": "", + "telegram_visible_messages_sent_by_collector": false +} diff --git a/docs/reports/leo-working-state-20260709/telegram-visible-unseen-chain-preflight-current.md b/docs/reports/leo-working-state-20260709/telegram-visible-unseen-chain-preflight-current.md new file mode 100644 index 0000000..c4e17c6 --- /dev/null +++ b/docs/reports/leo-working-state-20260709/telegram-visible-unseen-chain-preflight-current.md @@ -0,0 +1,49 @@ +# Telegram-Visible Unseen Chain Preflight + +Generated UTC: `2026-07-15T01:33:10.551000+00:00` +Status: `pass` +Protocol SHA256: `c815dad151d640335eecbddd2ca7bb651c43f6c1d4e53642e12c8a35157ac2da` +Packet file SHA256: `fb0ab4af0396b2064efce1ead44aacc0465ee0e3eacf9b4a7c07abae044d217a` +State token SHA256: `a0af7235b62f88a009184f8f51b6de4b9aec008f6d93ebfa1458f9b77fc208ec` +Messages sent by collector: `False` +Mutates DB: `False` + +## Checks + +- `packet_does_not_mutate_db`: `True` +- `packet_has_no_authorization_recorded`: `True` +- `packet_messages_exact`: `True` +- `packet_not_sent`: `True` +- `packet_prompt_ids_exact`: `True` +- `packet_protocol_sha256_present`: `True` +- `packet_ready_for_authorization_request`: `True` +- `packet_requires_authenticated_chrome`: `True` +- `packet_schema_supported`: `True` +- `packet_targets_exact_leo_chat`: `True` +- `packet_tooling_hashes_match_current_sources`: `True` +- `canonical_fingerprint_unchanged_during_probe`: `True` +- `deployed_stamp_is_ancestor_of_workspace_head`: `True` +- `deployed_stamp_is_sha`: `True` +- `fingerprints_are_read_only`: `True` +- `first_fingerprint_complete`: `True` +- `second_fingerprint_complete`: `True` +- `service_active_before_and_after`: `True` +- `service_identity_complete`: `True` +- `service_process_unchanged_during_probe`: `True` +- `ssh_readbacks_succeeded`: `True` +- `workspace_head_is_sha`: `True` + +## Live Readback + +- Deploy head: `15c30f1fbe30c8f2295ddc33e293a45788a95706` +- Deploy stamp: `15c30f1fbe30c8f2295ddc33e293a45788a95706` +- Gateway MainPID: `347406` +- Gateway NRestarts: `0` +- Canonical fingerprint: `32a1f2c18f4b4c623443cbd4d9520982e9f291ec74ca63855cef51c88ac56f24` +- Canonical tables: `39` +- Canonical rows: `52167` +- Selected object ref: `` + +## Claim Ceiling + +Two canonical read-only snapshots and the gateway process were unchanged during this probe. diff --git a/scripts/build_telegram_visible_unseen_chain_packet.py b/scripts/build_telegram_visible_unseen_chain_packet.py new file mode 100644 index 0000000..8a22800 --- /dev/null +++ b/scripts/build_telegram_visible_unseen_chain_packet.py @@ -0,0 +1,326 @@ +#!/usr/bin/env python3 +"""Build the exact no-send packet for Leo's unseen Telegram reasoning chain.""" + +from __future__ import annotations + +import argparse +import hashlib +import json +import subprocess +from datetime import datetime, timezone +from pathlib import Path +from typing import Any + +try: + import verify_leo_unseen_reasoning_chain as unseen +except ImportError: # pragma: no cover - imported as scripts.* in tests + from scripts import verify_leo_unseen_reasoning_chain as unseen + +SCHEMA = "livingip.telegramVisibleUnseenChainPacket.v1" +REPORT_DIR = Path("docs/reports/leo-working-state-20260709") +DEFAULT_HANDLER_RECEIPT = REPORT_DIR / "leo-unseen-reasoning-chain-canary-current.json" +DEFAULT_OUT = REPORT_DIR / "telegram-visible-unseen-chain-authorization-packet-current.json" +DEFAULT_MARKDOWN_OUT = REPORT_DIR / "telegram-visible-unseen-chain-authorization-packet-current.md" +DEFAULT_CAPTURE_RECEIPT = REPORT_DIR / "telegram-visible-unseen-chain-capture-receipt-current.json" +DEFAULT_PREFLIGHT = REPORT_DIR / "telegram-visible-unseen-chain-preflight-current.json" +DEFAULT_POSTFLIGHT = REPORT_DIR / "telegram-visible-unseen-chain-postflight-current.json" +DEFAULT_CHAT_ID = "-5146042086" +DEFAULT_CHAT_LABEL = "Leo" +DEFAULT_PROOF_DIR = "outputs/telegram-visible-unseen-chain-20260715" +TOOLING_PATHS = { + "packet_builder": Path("scripts/build_telegram_visible_unseen_chain_packet.py"), + "state_collector": Path("scripts/collect_telegram_visible_unseen_chain_state.py"), + "capture_verifier": Path("scripts/verify_telegram_visible_unseen_chain.py"), +} + + +def _load_json(path: Path) -> dict[str, Any]: + return json.loads(path.read_text(encoding="utf-8")) + + +def _sha256_bytes(value: bytes) -> str: + return hashlib.sha256(value).hexdigest() + + +def _sha256_file(path: Path) -> str: + return _sha256_bytes(path.read_bytes()) + + +def _canonical_sha256(value: Any) -> str: + encoded = json.dumps(value, sort_keys=True, separators=(",", ":")).encode("utf-8") + return _sha256_bytes(encoded) + + +def current_git_sha(repo_root: Path = Path(".")) -> str: + proc = subprocess.run( + ["git", "rev-parse", "HEAD"], + cwd=repo_root, + text=True, + capture_output=True, + check=False, + ) + return proc.stdout.strip() if proc.returncode == 0 else "" + + +def exact_messages() -> list[dict[str, Any]]: + messages = [] + for sequence, prompt in enumerate(unseen.PROMPTS, start=1): + message = str(prompt["message"]) + messages.append( + { + "sequence": sequence, + "prompt_id": prompt["id"], + "dimension": prompt["dimension"], + "message": message, + "message_sha256": _sha256_bytes(message.encode("utf-8")), + "wait_for_visible_reply_before_next": True, + } + ) + return messages + + +def tooling_binding(repo_root: Path = Path(".")) -> dict[str, dict[str, Any]]: + return {name: {"path": str(path), "sha256": _sha256_file(repo_root / path)} for name, path in TOOLING_PATHS.items()} + + +def _handler_checks(receipt: dict[str, Any]) -> dict[str, bool]: + safety = receipt.get("safety_gate") if isinstance(receipt.get("safety_gate"), dict) else {} + safety_checks = safety.get("checks") if isinstance(safety.get("checks"), dict) else {} + database = receipt.get("database") if isinstance(receipt.get("database"), dict) else {} + prompt_ids = [str(item["id"]) for item in unseen.PROMPTS] + return { + "handler_receipt_passed": receipt.get("status") == "pass", + "handler_receipt_schema_supported": receipt.get("schema") == unseen.SCHEMA, + "handler_prompt_ids_exact": receipt.get("prompt_ids") == prompt_ids, + "handler_outcomes_all_pass": bool(receipt.get("outcomes")) + and all(value is True for value in receipt.get("outcomes", {}).values()), + "handler_checks_all_pass": bool(receipt.get("checks")) + and all(value is True for value in receipt.get("checks", {}).values()), + "handler_safety_gate_passed": safety.get("status") == "pass", + "handler_proved_no_telegram_post": safety_checks.get("no_telegram_post") is True, + "handler_proved_read_only_tool_traces": safety_checks.get("all_tool_traces_read_only_and_bound") is True, + "handler_proved_unchanged_fingerprint": database.get("fingerprint_unchanged") is True + and isinstance(database.get("fingerprint_sha256"), str) + and len(database["fingerprint_sha256"]) == 64, + "handler_tier_remains_below_telegram_visible": "Telegram-visible message delivery" + in (receipt.get("claim_ceiling") or {}).get("not_proven", []), + } + + +def _authorization_text(*, chat_label: str, chat_id: str, messages: list[dict[str, Any]]) -> str: + quoted = " ".join(f"[{item['prompt_id']}] {json.dumps(item['message'], ensure_ascii=True)}" for item in messages) + return ( + "I authorize Codex to use the already-authenticated Chrome Telegram UI to send exactly these three " + f"messages, in order and with no additional messages, to the Telegram group {chat_label} (chat ID " + f"{chat_id}), waiting for Leo's visible reply after each turn: {quoted} Capture the visible replies, " + "message IDs, timestamps, screenshot and accessibility evidence; perform only read-only DB/service " + "readbacks; do not use the Bot API; do not stage, approve, apply, or otherwise mutate knowledge." + ) + + +def build_packet( + *, + handler_receipt_path: Path = DEFAULT_HANDLER_RECEIPT, + chat_id: str = DEFAULT_CHAT_ID, + chat_label: str = DEFAULT_CHAT_LABEL, + proof_dir: str = DEFAULT_PROOF_DIR, + git_sha: str | None = None, +) -> dict[str, Any]: + handler_receipt = _load_json(handler_receipt_path) + messages = exact_messages() + handler_checks = _handler_checks(handler_receipt) + target = { + "platform": "telegram", + "chat_label": chat_label, + "chat_id": chat_id, + "allowed_transport": "authenticated_chrome_telegram_ui", + "forbidden_transports": ["telegram_bot_api", "copied_transcript", "handler_substitution"], + "message_count": len(messages), + "expected_prompt_ids": [item["prompt_id"] for item in messages], + } + handler_binding = { + "path": str(handler_receipt_path), + "sha256": _sha256_file(handler_receipt_path), + "schema": handler_receipt.get("schema"), + "proof_tier": handler_receipt.get("proof_tier"), + "remote_run_id": handler_receipt.get("remote_run_id"), + "deployed_git_head": handler_receipt.get("deployed_git_head"), + "fingerprint_sha256": (handler_receipt.get("database") or {}).get("fingerprint_sha256"), + } + tooling = tooling_binding() + protocol = { + "target": target, + "exact_messages": messages, + "handler_binding": handler_binding, + "tooling_binding": tooling, + "state_contract": { + "preflight": "two identical repeatable-read read-only canonical fingerprints", + "postflight": "same canonical fingerprint plus independent selected-object readback", + "service": "same active gateway process before and after", + }, + } + protocol_sha256 = _canonical_sha256(protocol) + checks = { + **handler_checks, + "exact_three_turn_sequence": len(messages) == 3 and [item["sequence"] for item in messages] == [1, 2, 3], + "exact_prompts_imported_from_handler_verifier": [item["message"] for item in messages] + == [item["message"] for item in unseen.PROMPTS], + "first_prompt_supplies_no_row_id": unseen.UUID_RE.search(messages[0]["message"]) is None, + "authenticated_chrome_is_only_send_transport": target["allowed_transport"] + == "authenticated_chrome_telegram_ui", + "packet_does_not_send": True, + "packet_does_not_mutate_database": True, + } + ready = all(checks.values()) + authorization_text = _authorization_text(chat_label=chat_label, chat_id=chat_id, messages=messages) + proof_paths = { + "preflight_json": str(DEFAULT_PREFLIGHT), + "postflight_json": str(DEFAULT_POSTFLIGHT), + "capture_receipt_json": str(DEFAULT_CAPTURE_RECEIPT), + "capture_json": f"{proof_dir}/capture.json", + "turn_screenshots": [f"{proof_dir}/turn-{index}.png" for index in range(1, 4)], + "turn_accessibility": [f"{proof_dir}/turn-{index}-accessibility.txt" for index in range(1, 4)], + "final_screenshot": f"{proof_dir}/final.png", + "final_accessibility": f"{proof_dir}/final-accessibility.txt", + } + return { + "schema": SCHEMA, + "generated_at_utc": datetime.now(timezone.utc).isoformat(), + "mode": "telegram_visible_unseen_chain_exact_packet_not_sent", + "packet_generation_git_sha": git_sha if git_sha is not None else current_git_sha(), + "protocol_sha256": protocol_sha256, + "ready_to_request_action_time_authorization": ready, + "authorization_gate_status": "ready_to_request_exact_authorization" if ready else "not_ready", + "telegram_visible_messages_sent": False, + "telegram_visible_message_authorization_present": False, + "production_apply_executed": False, + "mutates_db": False, + "target": target, + "exact_messages": messages, + "handler_receipt_binding": handler_binding, + "tooling_binding": tooling, + "checks": checks, + "expected_proof_paths_after_authorized_run": proof_paths, + "explicit_operator_authorization_text": authorization_text, + "clear_CTA": ( + "Reply with the exact authorization sentence in this packet. That sentence names the destination, " + "transport, complete message bodies, ordering, evidence, and no-mutation boundary." + ), + "next_non_user_action_after_authorization": [ + "Re-run the zero-mutation preflight and confirm its packet file hash is current.", + "Use authenticated Chrome only and verify the Leo chat ID before typing anything.", + "Send one exact message, wait for Leo's visible reply, then continue to the next exact message.", + "Capture message IDs, timestamps, screenshot, and accessibility text without copying handler output.", + "Extract the selected DB object reference and run the read-only postflight with that reference.", + "Run the Telegram-visible verifier and accept T3 only if every visible and state check passes.", + ], + "claim_ceiling": { + "current_tier": "T0_spec_plus_prior_T2_handler_evidence", + "required_tier": "T3_live_readonly", + "proven": "The exact three-turn Chrome send packet is bound to a passing no-send handler receipt.", + "not_proven": [ + "Telegram-visible delivery of these three messages", + "Telegram-visible replies from Leo", + "post-send canonical fingerprint equality", + ], + }, + } + + +def write_json(path: Path, data: dict[str, Any]) -> None: + path.parent.mkdir(parents=True, exist_ok=True) + path.write_text(json.dumps(data, indent=2, sort_keys=True) + "\n", encoding="utf-8") + + +def write_markdown(path: Path, data: dict[str, Any]) -> None: + target = data["target"] + lines = [ + "# Telegram-Visible Unseen Chain Authorization Packet", + "", + f"Generated UTC: `{data['generated_at_utc']}`", + f"Protocol SHA256: `{data['protocol_sha256']}`", + f"Ready to request action-time authorization: `{data['ready_to_request_action_time_authorization']}`", + f"Telegram-visible messages sent: `{data['telegram_visible_messages_sent']}`", + f"Mutates DB: `{data['mutates_db']}`", + "", + "## Exact Destination", + "", + f"- Chat: `{target['chat_label']}` (`{target['chat_id']}`)", + f"- Transport: `{target['allowed_transport']}`", + "", + "## Exact Messages", + "", + ] + for item in data["exact_messages"]: + lines.extend( + [ + f"### {item['sequence']}. {item['prompt_id']}", + "", + item["message"], + "", + f"SHA256: `{item['message_sha256']}`", + "", + ] + ) + lines.extend(["## Checks", ""]) + lines.extend(f"- `{key}`: `{value}`" for key, value in sorted(data["checks"].items())) + lines.extend( + [ + "", + "## Exact Action-Time Authorization", + "", + data["explicit_operator_authorization_text"], + "", + "## Clear CTA", + "", + data["clear_CTA"], + "", + "## Claim Ceiling", + "", + f"Current tier: `{data['claim_ceiling']['current_tier']}`", + f"Required tier: `{data['claim_ceiling']['required_tier']}`", + "", + ] + ) + path.parent.mkdir(parents=True, exist_ok=True) + path.write_text("\n".join(lines), encoding="utf-8") + + +def parse_args(argv: list[str] | None = None) -> argparse.Namespace: + parser = argparse.ArgumentParser(description=__doc__) + parser.add_argument("--handler-receipt", type=Path, default=DEFAULT_HANDLER_RECEIPT) + parser.add_argument("--chat-id", default=DEFAULT_CHAT_ID) + parser.add_argument("--chat-label", default=DEFAULT_CHAT_LABEL) + parser.add_argument("--proof-dir", default=DEFAULT_PROOF_DIR) + parser.add_argument("--out", type=Path, default=DEFAULT_OUT) + parser.add_argument("--markdown-out", type=Path, default=DEFAULT_MARKDOWN_OUT) + return parser.parse_args(argv) + + +def main(argv: list[str] | None = None) -> int: + args = parse_args(argv) + data = build_packet( + handler_receipt_path=args.handler_receipt, + chat_id=args.chat_id, + chat_label=args.chat_label, + proof_dir=args.proof_dir, + ) + write_json(args.out, data) + write_markdown(args.markdown_out, data) + print( + json.dumps( + { + "out": str(args.out), + "markdown_out": str(args.markdown_out), + "ready_to_request_action_time_authorization": data["ready_to_request_action_time_authorization"], + "telegram_visible_messages_sent": False, + }, + indent=2, + sort_keys=True, + ) + ) + return 0 if data["ready_to_request_action_time_authorization"] else 2 + + +if __name__ == "__main__": + raise SystemExit(main()) diff --git a/scripts/collect_telegram_visible_unseen_chain_state.py b/scripts/collect_telegram_visible_unseen_chain_state.py new file mode 100644 index 0000000..2558539 --- /dev/null +++ b/scripts/collect_telegram_visible_unseen_chain_state.py @@ -0,0 +1,616 @@ +#!/usr/bin/env python3 +"""Collect fail-closed read-only state for the unseen Telegram chain.""" + +from __future__ import annotations + +import argparse +import hashlib +import json +import re +import shlex +import subprocess +from collections.abc import Callable +from dataclasses import dataclass +from datetime import datetime, timezone +from pathlib import Path +from typing import Any + +try: + import build_telegram_visible_unseen_chain_packet as packet_builder + import verify_leo_unseen_reasoning_chain as unseen +except ImportError: # pragma: no cover - imported as scripts.* in tests + from scripts import build_telegram_visible_unseen_chain_packet as packet_builder + from scripts import verify_leo_unseen_reasoning_chain as unseen + +SCHEMA = "livingip.telegramVisibleUnseenChainState.v1" +REPORT_DIR = Path("docs/reports/leo-working-state-20260709") +DEFAULT_PACKET = packet_builder.DEFAULT_OUT +DEFAULT_PREFLIGHT_OUT = REPORT_DIR / "telegram-visible-unseen-chain-preflight-current.json" +DEFAULT_PREFLIGHT_MARKDOWN_OUT = REPORT_DIR / "telegram-visible-unseen-chain-preflight-current.md" +DEFAULT_POSTFLIGHT_OUT = REPORT_DIR / "telegram-visible-unseen-chain-postflight-current.json" +DEFAULT_POSTFLIGHT_MARKDOWN_OUT = REPORT_DIR / "telegram-visible-unseen-chain-postflight-current.md" +DEFAULT_SSH_TARGET = "root@77.42.65.182" +DEFAULT_SSH_KEY = Path.home() / ".ssh/livingip_hetzner_20260604_ed25519" +DEFAULT_MANIFEST_SQL = Path("ops/postgres_parity_manifest.sql") +REMOTE_REPO = "/opt/teleo-eval/workspaces/deploy-infra" +SUBJECT_REF_RE = re.compile( + r"^(?:[0-9a-f]{8}|[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12})$", + re.IGNORECASE, +) +SHA40_RE = re.compile(r"^[0-9a-f]{40}$") + + +@dataclass(frozen=True) +class CommandResult: + returncode: int + stdout: str + stderr: str + + +Runner = Callable[[list[str], str, int], CommandResult] + + +def subprocess_runner(command: list[str], input_text: str, timeout: int) -> CommandResult: + try: + proc = subprocess.run( + command, + input=input_text, + text=True, + capture_output=True, + timeout=timeout, + check=False, + ) + except subprocess.TimeoutExpired as exc: + return CommandResult(124, str(exc.stdout or ""), f"command timed out after {timeout}s") + return CommandResult(proc.returncode, proc.stdout, proc.stderr) + + +def _load_json(path: Path) -> dict[str, Any]: + return json.loads(path.read_text(encoding="utf-8")) + + +def _canonical_sha256(value: Any) -> str: + encoded = json.dumps(value, sort_keys=True, separators=(",", ":")).encode("utf-8") + return hashlib.sha256(encoded).hexdigest() + + +def _sha256_file(path: Path) -> str: + return hashlib.sha256(path.read_bytes()).hexdigest() + + +def parse_key_value_lines(text: str) -> dict[str, str]: + values: dict[str, str] = {} + for line in text.splitlines(): + if "=" not in line: + continue + key, value = line.split("=", 1) + values[key] = value.strip() + return values + + +def parse_manifest_output(raw: str) -> dict[str, Any]: + rows = [] + try: + for line in raw.splitlines(): + candidate = line.strip() + if not candidate or candidate in {"BEGIN", "SET", "ROLLBACK"}: + continue + value = json.loads(candidate) + if isinstance(value, dict): + rows.append(value) + except (TypeError, json.JSONDecodeError) as exc: + return {"status": "error", "error": f"manifest_parse_error:{type(exc).__name__}"} + + tables = { + f"{row['schema']}.{row['table']}": { + "row_count": int(row["row_count"]), + "rowset_md5": row["rowset_md5"], + } + for row in rows + if row.get("kind") == "table" + } + singleton_kinds = { + "schemas", + "extensions", + "application_roles", + "columns", + "constraints", + "indexes", + "sequences", + "views", + "functions", + "triggers", + "types", + "policies", + } + singleton = {str(row["kind"]): row.get("items", []) for row in rows if row.get("kind") in singleton_kinds} + identity_rows = [row for row in rows if row.get("kind") == "identity"] + if len(identity_rows) != 1 or not tables or singleton_kinds - set(singleton): + return {"status": "error", "error": "canonical_database_fingerprint_manifest_incomplete"} + identity = identity_rows[0] + stable = { + "identity": { + key: identity.get(key) + for key in ( + "database", + "server_version_num", + "server_encoding", + "database_collation", + "database_ctype", + "transaction_read_only", + ) + }, + "singleton_sha256": {key: _canonical_sha256(value) for key, value in sorted(singleton.items())}, + "tables": tables, + } + return { + "schema": "livingip.teleoCanonicalDatabaseFingerprint.v1", + "status": "ok", + "fingerprint_sha256": _canonical_sha256(stable), + "table_count": len(tables), + "total_rows": sum(item["row_count"] for item in tables.values()), + "table_rows_sha256": _canonical_sha256(tables), + "structure_sha256": _canonical_sha256(stable["singleton_sha256"]), + "transaction_read_only": identity.get("transaction_read_only"), + } + + +def packet_checks(packet: dict[str, Any]) -> dict[str, bool]: + target = packet.get("target") if isinstance(packet.get("target"), dict) else {} + exact = packet_builder.exact_messages() + expected_tooling = packet_builder.tooling_binding() + return { + "packet_schema_supported": packet.get("schema") == packet_builder.SCHEMA, + "packet_ready_for_authorization_request": packet.get("ready_to_request_action_time_authorization") is True, + "packet_not_sent": packet.get("telegram_visible_messages_sent") is False, + "packet_has_no_authorization_recorded": packet.get("telegram_visible_message_authorization_present") is False, + "packet_does_not_mutate_db": packet.get("mutates_db") is False, + "packet_targets_exact_leo_chat": target.get("chat_label") == packet_builder.DEFAULT_CHAT_LABEL + and target.get("chat_id") == packet_builder.DEFAULT_CHAT_ID, + "packet_requires_authenticated_chrome": target.get("allowed_transport") == "authenticated_chrome_telegram_ui", + "packet_prompt_ids_exact": target.get("expected_prompt_ids") == [item["id"] for item in unseen.PROMPTS], + "packet_messages_exact": [item.get("message") for item in packet.get("exact_messages", [])] + == [item["message"] for item in exact], + "packet_protocol_sha256_present": isinstance(packet.get("protocol_sha256"), str) + and len(packet["protocol_sha256"]) == 64, + "packet_tooling_hashes_match_current_sources": packet.get("tooling_binding") == expected_tooling, + } + + +def ssh_command(args: argparse.Namespace, remote_command: str) -> list[str]: + return [ + "ssh", + "-i", + str(args.ssh_key), + "-o", + "BatchMode=yes", + "-o", + "StrictHostKeyChecking=accept-new", + "-o", + f"ConnectTimeout={args.connect_timeout}", + args.ssh_target, + remote_command, + ] + + +def deploy_readback_command() -> str: + repo = shlex.quote(REMOTE_REPO) + return ( + f"cd {repo} && " + "deploy_head=$(git rev-parse HEAD) && " + "last_deploy_sha=$(cat /opt/teleo-eval/.last-deploy-sha) && " + 'printf \'deploy_head=%s\\nlast_deploy_sha=%s\\n\' "$deploy_head" "$last_deploy_sha" && ' + 'if git merge-base --is-ancestor "$last_deploy_sha" "$deploy_head"; then ' + "printf 'deploy_stamp_ancestor=true\\n'; else printf 'deploy_stamp_ancestor=false\\n'; fi" + ) + + +def service_readback_command() -> str: + return ( + "systemctl show leoclean-gateway.service " + "-p ActiveState -p SubState -p MainPID -p NRestarts -p ExecMainStartTimestamp --no-pager" + ) + + +def fingerprint_readback_command() -> str: + return "docker exec -i teleo-pg psql -U postgres -d teleo -At -q -v ON_ERROR_STOP=1" + + +def subject_readback_sql(subject_ref: str) -> str: + if not SUBJECT_REF_RE.fullmatch(subject_ref): + raise ValueError("subject_ref must be an eight-hex prefix or UUID") + prefix = subject_ref.casefold() + return f""" +\\set ON_ERROR_STOP on +begin transaction isolation level repeatable read read only; +select jsonb_build_object( + 'subject_ref', '{prefix}', + 'matches', coalesce(jsonb_agg(item order by item->>'table', item->'row'->>'id'), '[]'::jsonb) +)::text +from ( + select jsonb_build_object( + 'table', 'public.claims', + 'row', to_jsonb(claim_row), + 'evidence_count', (select count(*) from public.claim_evidence evidence where evidence.claim_id = claim_row.id) + ) as item + from public.claims claim_row + where lower(claim_row.id::text) like '{prefix}%' + union all + select jsonb_build_object( + 'table', 'public.beliefs', + 'row', to_jsonb(belief_row), + 'evidence_count', null + ) as item + from public.beliefs belief_row + where lower(belief_row.id::text) like '{prefix}%' +) matched; +rollback; +""".strip() + + +def _parse_single_json_line(raw: str) -> dict[str, Any] | None: + for line in raw.splitlines(): + candidate = line.strip() + if not candidate or candidate in {"BEGIN", "SET", "ROLLBACK"}: + continue + try: + value = json.loads(candidate) + except json.JSONDecodeError: + continue + if isinstance(value, dict): + return value + return None + + +def collect_remote(args: argparse.Namespace, runner: Runner) -> tuple[dict[str, Any], int, str]: + manifest_sql = args.manifest_sql.read_text(encoding="utf-8") + calls: list[tuple[str, list[str], str, int]] = [ + ("deploy", ssh_command(args, deploy_readback_command()), "", args.timeout), + ("service_before", ssh_command(args, service_readback_command()), "", args.timeout), + ( + "fingerprint_before", + ssh_command(args, fingerprint_readback_command()), + manifest_sql, + args.fingerprint_timeout, + ), + ( + "fingerprint_after", + ssh_command(args, fingerprint_readback_command()), + manifest_sql, + args.fingerprint_timeout, + ), + ("service_after", ssh_command(args, service_readback_command()), "", args.timeout), + ] + if args.subject_ref: + calls.append( + ( + "subject", + ssh_command(args, fingerprint_readback_command()), + subject_readback_sql(args.subject_ref), + args.timeout, + ) + ) + results: dict[str, CommandResult] = {} + attempts: dict[str, int] = {} + for name, command, input_text, timeout in calls: + result = CommandResult(1, "", "not attempted") + for attempt in range(1, max(1, args.ssh_attempts) + 1): + result = runner(command, input_text, timeout) + attempts[name] = attempt + if result.returncode == 0: + break + results[name] = result + deploy_values = parse_key_value_lines(results["deploy"].stdout) + service_before = parse_key_value_lines(results["service_before"].stdout) + service_after = parse_key_value_lines(results["service_after"].stdout) + fingerprint_before = parse_manifest_output(results["fingerprint_before"].stdout) + fingerprint_after = parse_manifest_output(results["fingerprint_after"].stdout) + subject = _parse_single_json_line(results["subject"].stdout) if "subject" in results else None + returncode = next((result.returncode for result in results.values() if result.returncode != 0), 0) + stderr = "\n".join(f"{name}: {result.stderr.strip()}" for name, result in results.items() if result.stderr.strip()) + return ( + { + "deploy_head": deploy_values.get("deploy_head", ""), + "last_deploy_sha": deploy_values.get("last_deploy_sha", ""), + "deploy_stamp_ancestor": deploy_values.get("deploy_stamp_ancestor") == "true", + "workspace_head_matches_deployed_stamp": deploy_values.get("deploy_head") + == deploy_values.get("last_deploy_sha"), + "service_before": service_before, + "service_after": service_after, + "fingerprint_before": fingerprint_before, + "fingerprint_after": fingerprint_after, + "subject_readback": subject, + "readback_attempts": attempts, + }, + returncode, + stderr, + ) + + +def _service_active(state: dict[str, Any]) -> bool: + return state.get("ActiveState") == "active" and state.get("SubState") == "running" + + +def _service_identity(state: dict[str, Any]) -> dict[str, Any]: + return {key: state.get(key) for key in ("MainPID", "NRestarts", "ExecMainStartTimestamp")} + + +def _remote_checks( + remote: dict[str, Any], + *, + returncode: int, + subject_required: bool, + expected_subject_ref: str | None, +) -> dict[str, bool]: + before = remote.get("fingerprint_before") or {} + after = remote.get("fingerprint_after") or {} + service_before = remote.get("service_before") or {} + service_after = remote.get("service_after") or {} + subject = remote.get("subject_readback") or {} + matches = subject.get("matches") if isinstance(subject, dict) else None + checks = { + "ssh_readbacks_succeeded": returncode == 0, + "workspace_head_is_sha": bool(SHA40_RE.fullmatch(str(remote.get("deploy_head") or ""))), + "deployed_stamp_is_sha": bool(SHA40_RE.fullmatch(str(remote.get("last_deploy_sha") or ""))), + "deployed_stamp_is_ancestor_of_workspace_head": remote.get("deploy_stamp_ancestor") is True, + "service_active_before_and_after": _service_active(service_before) and _service_active(service_after), + "service_identity_complete": all( + value + for value in ( + service_before.get("MainPID"), + service_before.get("NRestarts"), + service_before.get("ExecMainStartTimestamp"), + service_after.get("MainPID"), + service_after.get("NRestarts"), + service_after.get("ExecMainStartTimestamp"), + ) + ), + "service_process_unchanged_during_probe": _service_identity(service_before) == _service_identity(service_after), + "first_fingerprint_complete": before.get("status") == "ok" and int(before.get("table_count") or 0) > 0, + "second_fingerprint_complete": after.get("status") == "ok" and int(after.get("table_count") or 0) > 0, + "fingerprints_are_read_only": before.get("transaction_read_only") == "on" + and after.get("transaction_read_only") == "on", + "canonical_fingerprint_unchanged_during_probe": bool(before.get("fingerprint_sha256")) + and before.get("fingerprint_sha256") == after.get("fingerprint_sha256"), + } + if subject_required: + checks.update( + { + "subject_readback_present": isinstance(subject, dict), + "subject_reference_matches_request": subject.get("subject_ref") + == str(expected_subject_ref or "").casefold(), + "subject_resolved_to_exactly_one_db_object": isinstance(matches, list) and len(matches) == 1, + } + ) + return checks + + +def collect_state(args: argparse.Namespace, *, runner: Runner = subprocess_runner) -> dict[str, Any]: + packet = _load_json(args.packet) + local_packet_checks = packet_checks(packet) + remote, remote_returncode, remote_stderr = collect_remote(args, runner) + remote_checks = _remote_checks( + remote, + returncode=remote_returncode, + subject_required=args.phase == "postflight", + expected_subject_ref=args.subject_ref, + ) + baseline = _load_json(args.baseline) if args.baseline else None + baseline_checks: dict[str, bool] = {} + if args.phase == "postflight": + baseline_checks = { + "baseline_supplied": baseline is not None, + "baseline_is_passing_preflight": bool( + baseline and baseline.get("phase") == "preflight" and baseline.get("status") == "pass" + ), + "baseline_protocol_matches_packet": bool( + baseline and baseline.get("protocol_sha256") == packet.get("protocol_sha256") + ), + "baseline_packet_file_matches": bool( + baseline and baseline.get("packet_file_sha256") == _sha256_file(args.packet) + ), + "canonical_fingerprint_matches_preflight": bool( + baseline + and (baseline.get("remote") or {}).get("fingerprint_after", {}).get("fingerprint_sha256") + == remote.get("fingerprint_after", {}).get("fingerprint_sha256") + ), + "gateway_process_matches_preflight": bool( + baseline + and _service_identity((baseline.get("remote") or {}).get("service_after") or {}) + == _service_identity(remote.get("service_after") or {}) + ), + } + status = ( + "pass" + if all(local_packet_checks.values()) and all(remote_checks.values()) and all(baseline_checks.values()) + else "fail" + ) + packet_file_sha256 = _sha256_file(args.packet) + state_token = _canonical_sha256( + { + "phase": args.phase, + "packet_file_sha256": packet_file_sha256, + "protocol_sha256": packet.get("protocol_sha256"), + "deploy_head": remote.get("deploy_head"), + "service": _service_identity(remote.get("service_after") or {}), + "fingerprint": remote.get("fingerprint_after"), + "subject_readback": remote.get("subject_readback"), + } + ) + exact_gate = "" + if status != "pass": + failed = [ + key + for checks in (local_packet_checks, remote_checks, baseline_checks) + for key, value in checks.items() + if value is not True + ] + exact_gate = remote_stderr.strip() or ", ".join(failed) + current_canary = ( + "Read-only pre-send readiness for the exact three-turn unseen Leo chain in Telegram" + if args.phase == "preflight" + else "Read-only post-send DB grounding and unchanged-state proof for the exact Telegram chain" + ) + return { + "schema": SCHEMA, + "generated_at_utc": datetime.now(timezone.utc).isoformat(), + "mode": "telegram_visible_unseen_chain_zero_mutation_state_readback", + "phase": args.phase, + "status": status, + "ready_for_action_time_authorization": args.phase == "preflight" and status == "pass", + "ready_for_visible_capture_verification": args.phase == "postflight" and status == "pass", + "telegram_visible_messages_sent_by_collector": False, + "production_apply_executed": False, + "mutates_db": False, + "packet_path": str(args.packet), + "packet_file_sha256": packet_file_sha256, + "protocol_sha256": packet.get("protocol_sha256"), + "baseline_path": str(args.baseline) if args.baseline else "", + "subject_ref": args.subject_ref or "", + "state_token_sha256": state_token, + "packet_checks": local_packet_checks, + "remote_checks": remote_checks, + "baseline_checks": baseline_checks, + "remote": remote, + "remote_returncode": remote_returncode, + "remote_stderr": remote_stderr, + "blocker_readback": { + "current_canary": current_canary, + "attempted_routes": [ + "local exact packet validation", + "SSH deploy stamp and gateway service readback", + "two canonical repeatable-read read-only Postgres parity manifests", + *(["independent selected-object DB readback"] if args.subject_ref else []), + ], + "exact_gate": exact_gate, + "clear_CTA": ( + "No user action is needed; repair the named readback check and rerun this collector." + if exact_gate + else "Use the packet's exact authorization sentence only when ready to cross the send boundary." + ), + "next_non_user_action": ( + "Run the authenticated-Chrome three-turn flow only after exact authorization, then collect postflight." + if args.phase == "preflight" and status == "pass" + else "Repair the failed preflight check and rerun before requesting authorization." + if args.phase == "preflight" + else "Run the visible capture verifier against this postflight and the retained Chrome evidence." + ), + }, + "claim_ceiling": { + "current_tier": "T3_live_readonly" if status == "pass" else "T0_failed_preflight", + "proven": ( + "Two canonical read-only snapshots and the gateway process were unchanged during this probe." + if status == "pass" + else "No live readiness claim; one or more fail-closed checks did not pass." + ), + "not_proven": [ + "Telegram-visible delivery or reply behavior", + "authorization to send Telegram messages", + "canonical mutation", + ], + }, + } + + +def write_json(path: Path, data: dict[str, Any]) -> None: + path.parent.mkdir(parents=True, exist_ok=True) + path.write_text(json.dumps(data, indent=2, sort_keys=True) + "\n", encoding="utf-8") + + +def write_markdown(path: Path, data: dict[str, Any]) -> None: + remote = data.get("remote") or {} + service = remote.get("service_after") or {} + fingerprint = remote.get("fingerprint_after") or {} + lines = [ + f"# Telegram-Visible Unseen Chain {data['phase'].title()}", + "", + f"Generated UTC: `{data['generated_at_utc']}`", + f"Status: `{data['status']}`", + f"Protocol SHA256: `{data['protocol_sha256']}`", + f"Packet file SHA256: `{data['packet_file_sha256']}`", + f"State token SHA256: `{data['state_token_sha256']}`", + f"Messages sent by collector: `{data['telegram_visible_messages_sent_by_collector']}`", + f"Mutates DB: `{data['mutates_db']}`", + "", + "## Checks", + "", + ] + for section in ("packet_checks", "remote_checks", "baseline_checks"): + for key, value in sorted(data.get(section, {}).items()): + lines.append(f"- `{key}`: `{value}`") + lines.extend( + [ + "", + "## Live Readback", + "", + f"- Deploy head: `{remote.get('deploy_head', '')}`", + f"- Deploy stamp: `{remote.get('last_deploy_sha', '')}`", + f"- Gateway MainPID: `{service.get('MainPID', '')}`", + f"- Gateway NRestarts: `{service.get('NRestarts', '')}`", + f"- Canonical fingerprint: `{fingerprint.get('fingerprint_sha256', '')}`", + f"- Canonical tables: `{fingerprint.get('table_count', '')}`", + f"- Canonical rows: `{fingerprint.get('total_rows', '')}`", + f"- Selected object ref: `{data.get('subject_ref', '')}`", + "", + "## Claim Ceiling", + "", + data["claim_ceiling"]["proven"], + "", + ] + ) + path.parent.mkdir(parents=True, exist_ok=True) + path.write_text("\n".join(lines), encoding="utf-8") + + +def parse_args(argv: list[str] | None = None) -> argparse.Namespace: + parser = argparse.ArgumentParser(description=__doc__) + parser.add_argument("--phase", choices=("preflight", "postflight"), default="preflight") + parser.add_argument("--packet", type=Path, default=DEFAULT_PACKET) + parser.add_argument("--baseline", type=Path) + parser.add_argument("--subject-ref") + parser.add_argument("--manifest-sql", type=Path, default=DEFAULT_MANIFEST_SQL) + parser.add_argument("--ssh-target", default=DEFAULT_SSH_TARGET) + parser.add_argument("--ssh-key", type=Path, default=DEFAULT_SSH_KEY) + parser.add_argument("--connect-timeout", type=int, default=10) + parser.add_argument("--timeout", type=int, default=60) + parser.add_argument("--fingerprint-timeout", type=int, default=240) + parser.add_argument("--ssh-attempts", type=int, default=3) + parser.add_argument("--out", type=Path) + parser.add_argument("--markdown-out", type=Path) + args = parser.parse_args(argv) + if args.phase == "postflight" and (not args.baseline or not args.subject_ref): + parser.error("postflight requires --baseline and --subject-ref") + if args.subject_ref and not SUBJECT_REF_RE.fullmatch(args.subject_ref): + parser.error("--subject-ref must be an eight-hex prefix or UUID") + if args.out is None: + args.out = DEFAULT_PREFLIGHT_OUT if args.phase == "preflight" else DEFAULT_POSTFLIGHT_OUT + if args.markdown_out is None: + args.markdown_out = ( + DEFAULT_PREFLIGHT_MARKDOWN_OUT if args.phase == "preflight" else DEFAULT_POSTFLIGHT_MARKDOWN_OUT + ) + return args + + +def main(argv: list[str] | None = None) -> int: + args = parse_args(argv) + data = collect_state(args) + write_json(args.out, data) + write_markdown(args.markdown_out, data) + print( + json.dumps( + { + "out": str(args.out), + "markdown_out": str(args.markdown_out), + "phase": args.phase, + "status": data["status"], + "mutates_db": False, + }, + indent=2, + sort_keys=True, + ) + ) + return 0 if data["status"] == "pass" else 2 + + +if __name__ == "__main__": + raise SystemExit(main()) diff --git a/scripts/verify_telegram_visible_unseen_chain.py b/scripts/verify_telegram_visible_unseen_chain.py new file mode 100644 index 0000000..8a92450 --- /dev/null +++ b/scripts/verify_telegram_visible_unseen_chain.py @@ -0,0 +1,524 @@ +#!/usr/bin/env python3 +"""Verify retained authenticated-Chrome proof for Leo's unseen Telegram chain.""" + +from __future__ import annotations + +import argparse +import hashlib +import json +import re +from datetime import datetime, timezone +from pathlib import Path +from typing import Any + +try: + import build_telegram_visible_unseen_chain_packet as packet_builder + import verify_leo_unseen_reasoning_chain as unseen +except ImportError: # pragma: no cover - imported as scripts.* in tests + from scripts import build_telegram_visible_unseen_chain_packet as packet_builder + from scripts import verify_leo_unseen_reasoning_chain as unseen + +SCHEMA = "livingip.telegramVisibleUnseenChainReceipt.v1" +REPORT_DIR = Path("docs/reports/leo-working-state-20260709") +DEFAULT_PACKET = packet_builder.DEFAULT_OUT +DEFAULT_PREFLIGHT = REPORT_DIR / "telegram-visible-unseen-chain-preflight-current.json" +DEFAULT_POSTFLIGHT = REPORT_DIR / "telegram-visible-unseen-chain-postflight-current.json" +DEFAULT_OUT = REPORT_DIR / "telegram-visible-unseen-chain-capture-receipt-current.json" +DEFAULT_MARKDOWN_OUT = REPORT_DIR / "telegram-visible-unseen-chain-capture-receipt-current.md" + + +def _load_json(path: Path) -> dict[str, Any]: + return json.loads(path.read_text(encoding="utf-8")) + + +def _sha256_file(path: Path) -> str: + return hashlib.sha256(path.read_bytes()).hexdigest() + + +def _present(value: Any) -> bool: + if value is None: + return False + if isinstance(value, str): + return bool(value.strip()) + if isinstance(value, (dict, list)): + return bool(value) + return True + + +def blank_capture_template(packet: dict[str, Any], preflight: dict[str, Any]) -> dict[str, Any]: + target = packet.get("target") or {} + return { + "protocol_sha256": packet.get("protocol_sha256"), + "preflight_state_token_sha256": preflight.get("state_token_sha256"), + "operator_authorization_text": packet.get("explicit_operator_authorization_text"), + "operator_authorization_captured_at_utc": "", + "extra_messages_sent": 0, + "capture_source": { + "platform": "telegram", + "transport": "authenticated_chrome_telegram_ui", + "chat_label": target.get("chat_label"), + "chat_id": target.get("chat_id"), + "captured_at_utc": "", + "captured_by": "", + "final_screenshot": "", + "final_accessibility": "", + }, + "messages": [ + { + "sequence": item["sequence"], + "prompt_id": item["prompt_id"], + "sent_text": item["message"], + "reply": "", + "sent_at_utc": "", + "reply_at_utc": "", + "telegram_message_id": "", + "reply_message_id": "", + "turn_screenshot": "", + "turn_accessibility": "", + } + for item in packet.get("exact_messages", []) + ], + } + + +def _resolve_evidence(path_value: str, evidence_root: Path) -> dict[str, Any]: + if not path_value.strip(): + return {"path": path_value, "exists": False, "bytes": 0, "sha256": ""} + path = Path(path_value) + if not path.is_absolute(): + path = evidence_root / path + resolved = path.resolve() + exists = resolved.is_file() + return { + "path": str(resolved), + "exists": exists, + "bytes": resolved.stat().st_size if exists else 0, + "sha256": _sha256_file(resolved) if exists else "", + } + + +def _capture_messages(capture: dict[str, Any]) -> list[dict[str, Any]]: + messages = capture.get("messages") + return [item for item in messages if isinstance(item, dict)] if isinstance(messages, list) else [] + + +def _normalized_text(value: str) -> str: + return re.sub(r"\s+", " ", value).strip().casefold() + + +def _accessibility_binds_message(evidence: dict[str, Any], *, sent_text: str, reply: str) -> bool: + if not evidence.get("exists") or not evidence.get("path"): + return False + text = Path(str(evidence["path"])).read_text(encoding="utf-8", errors="replace") + normalized = _normalized_text(text) + return _normalized_text(sent_text) in normalized and _normalized_text(reply) in normalized + + +def _subject_match(postflight: dict[str, Any]) -> dict[str, Any]: + subject = (postflight.get("remote") or {}).get("subject_readback") or {} + matches = subject.get("matches") if isinstance(subject, dict) else [] + return matches[0] if isinstance(matches, list) and len(matches) == 1 else {} + + +def _semantic_checks(replies: list[str], *, subject_ref: str, subject_match: dict[str, Any]) -> dict[str, bool]: + if len(replies) != 3: + return { + "visible_db_object_selected_without_operator_id": False, + "visible_weak_support_explained": False, + "same_subject_survived_challenge": False, + "assumption_support_and_falsifier_separated": False, + "multiple_review_only_candidates_proposed": False, + "objection_revised_candidate": False, + "resolving_source_named": False, + "review_approval_apply_boundary_explicit": False, + "reply_claimed_no_mutation": False, + "independent_db_object_matches_visible_subject": False, + } + first, second, third = replies + first_refs = unseen._short_refs(first) + second_refs = unseen._short_refs(second) + shared_terms = unseen._shared_subject_terms(first, second) + selected = subject_ref[:8].casefold() if subject_ref else "" + visible_subject = bool(selected and (selected in first.casefold() or selected in second.casefold())) + same_subject = bool( + visible_subject + and ( + (selected in first.casefold() and selected in second.casefold()) + or first_refs & second_refs + or len(shared_terms) >= 2 + ) + ) + row = subject_match.get("row") if isinstance(subject_match.get("row"), dict) else {} + row_id = str(row.get("id") or "").casefold() + proposals = unseen._contains(second, "proposal a", "proposal b") or ( + unseen._contains_any(second, "two proposals", "two replacement claims") and "1" in second and "2" in second + ) + return { + "visible_db_object_selected_without_operator_id": unseen._contains_any(first, "claim", "belief", "axiom") + and unseen._contains_any(first, "database", "db", "public.") + and unseen._contains_any(first, "confidence", "support", "evidence"), + "visible_weak_support_explained": unseen._contains_any( + first, + "nothing supports", + "zero evidence", + "no evidence", + "no claim-evidence", + "no_source_pointer", + "no external primary source", + ), + "same_subject_survived_challenge": same_subject, + "assumption_support_and_falsifier_separated": unseen._contains_any(second, "assumption") + and unseen._contains_any(second, "observed support", "evidence") + and unseen._contains_any(second, "falsifier", "counterexample", "would falsify"), + "multiple_review_only_candidates_proposed": proposals + and unseen._contains_any(second, "review", "staged", "proposal") + and unseen._contains_any( + second, + "nothing applied", + "not live knowledge", + "staged only", + "not an apply", + ), + "objection_revised_candidate": unseen._contains_any(third, "revised proposal", "revision") + and unseen._contains(third, "mechanism", "outcome"), + "resolving_source_named": unseen._contains_any( + third, "what would resolve", "source would resolve", "evidence would resolve" + ) + and unseen._contains_any( + third, + "study", + "dataset", + "source", + "randomized", + "quasi-experimental", + "replication", + "ostrom", + ), + "review_approval_apply_boundary_explicit": unseen._contains_any( + third, "review", "pending_review", "human review" + ) + and unseen._contains_any(third, "approve", "approved", "approval") + and unseen._contains_any(third, "apply", "applied_at", "canonical"), + "reply_claimed_no_mutation": unseen._contains_any( + third, + "not an apply", + "nothing staged or changed", + "canonical unchanged", + "staged intent, not knowledge", + "proposal (not an apply)", + ), + "independent_db_object_matches_visible_subject": bool( + visible_subject and row_id and row_id.startswith(selected) + ), + } + + +def verify_capture( + packet: dict[str, Any], + preflight: dict[str, Any], + capture: dict[str, Any] | None, + postflight: dict[str, Any] | None, + *, + packet_path: Path, + evidence_root: Path, +) -> dict[str, Any]: + if capture is None: + return { + "schema": SCHEMA, + "generated_at_utc": datetime.now(timezone.utc).isoformat(), + "mode": "telegram_visible_unseen_chain_capture_verifier", + "status": "awaiting_action_time_authorization", + "receipt_ready": False, + "current_tier": "T0_packet_plus_T3_preflight", + "required_tier": "T3_live_readonly", + "telegram_visible_messages_sent": False, + "mutates_db": False, + "packet_path": str(packet_path), + "preflight_path": str(DEFAULT_PREFLIGHT), + "postflight_path": str(DEFAULT_POSTFLIGHT), + "capture_template": blank_capture_template(packet, preflight), + "checks": { + "packet_ready": packet.get("ready_to_request_action_time_authorization") is True, + "preflight_passed": preflight.get("status") == "pass", + "action_time_authorization_present": False, + "capture_present": False, + "postflight_present": False, + }, + "claim_ceiling": { + "proven": "The exact packet and live zero-mutation preflight are ready.", + "not_proven": [ + "Telegram-visible message delivery", + "Telegram-visible Leo replies", + "post-send fingerprint equality", + ], + }, + } + + messages = _capture_messages(capture) + expected = packet.get("exact_messages") or [] + capture_source = capture.get("capture_source") if isinstance(capture.get("capture_source"), dict) else {} + replies = [str(item.get("reply") or "") for item in messages] + ids = [str(item.get("telegram_message_id") or "") for item in messages] + reply_ids = [str(item.get("reply_message_id") or "") for item in messages] + screenshot = _resolve_evidence(str(capture_source.get("final_screenshot") or ""), evidence_root) + accessibility = _resolve_evidence(str(capture_source.get("final_accessibility") or ""), evidence_root) + turn_evidence = [ + { + "prompt_id": item.get("prompt_id"), + "screenshot": _resolve_evidence(str(item.get("turn_screenshot") or ""), evidence_root), + "accessibility": _resolve_evidence(str(item.get("turn_accessibility") or ""), evidence_root), + } + for item in messages + ] + postflight = postflight or {} + subject_ref = str(postflight.get("subject_ref") or "") + subject_match = _subject_match(postflight) + semantics = _semantic_checks(replies, subject_ref=subject_ref, subject_match=subject_match) + pre_fingerprint = (preflight.get("remote") or {}).get("fingerprint_after") or {} + post_fingerprint = (postflight.get("remote") or {}).get("fingerprint_after") or {} + pre_service = (preflight.get("remote") or {}).get("service_after") or {} + post_service = (postflight.get("remote") or {}).get("service_after") or {} + service_keys = ("MainPID", "NRestarts", "ExecMainStartTimestamp") + handler_binding = packet.get("handler_receipt_binding") or {} + handler_path = Path(str(handler_binding.get("path") or "")) + if not handler_path.is_absolute(): + handler_path = evidence_root / handler_path + expected_ids = [str(item.get("prompt_id") or "") for item in expected] + actual_ids = [str(item.get("prompt_id") or "") for item in messages] + checks = { + "packet_ready": packet.get("ready_to_request_action_time_authorization") is True, + "packet_file_hash_matches_preflight": _sha256_file(packet_path) == preflight.get("packet_file_sha256"), + "handler_receipt_binding_unchanged": handler_path.is_file() + and _sha256_file(handler_path) == handler_binding.get("sha256"), + "preflight_passed": preflight.get("status") == "pass" and preflight.get("phase") == "preflight", + "postflight_passed": postflight.get("status") == "pass" and postflight.get("phase") == "postflight", + "protocol_bound_across_all_artifacts": capture.get("protocol_sha256") + == preflight.get("protocol_sha256") + == postflight.get("protocol_sha256") + == packet.get("protocol_sha256"), + "preflight_state_token_bound_to_capture": capture.get("preflight_state_token_sha256") + == preflight.get("state_token_sha256"), + "exact_action_time_authorization_captured": capture.get("operator_authorization_text") + == packet.get("explicit_operator_authorization_text") + and _present(capture.get("operator_authorization_captured_at_utc")), + "authenticated_chrome_transport_proven": capture_source.get("platform") == "telegram" + and capture_source.get("transport") == "authenticated_chrome_telegram_ui", + "bot_api_not_substituted": "bot_api" not in json.dumps(capture_source).casefold(), + "exact_destination_matches": capture_source.get("chat_label") == (packet.get("target") or {}).get("chat_label") + and capture_source.get("chat_id") == (packet.get("target") or {}).get("chat_id"), + "exact_three_messages_and_no_extras": len(messages) == len(expected) == 3 + and capture.get("extra_messages_sent") == 0, + "prompt_ids_and_sequence_exact": actual_ids == expected_ids + and [item.get("sequence") for item in messages] == [1, 2, 3], + "sent_text_exact": [item.get("sent_text") for item in messages] == [item.get("message") for item in expected], + "visible_replies_nonempty": len(replies) == 3 and all(reply.strip() for reply in replies), + "message_and_reply_ids_present_unique": all(ids) + and all(reply_ids) + and len(set(ids)) == 3 + and len(set(reply_ids)) == 3, + "message_and_reply_timestamps_present": all( + _present(item.get("sent_at_utc")) and _present(item.get("reply_at_utc")) for item in messages + ), + "capture_metadata_present": all( + _present(capture_source.get(key)) for key in ("captured_at_utc", "captured_by") + ), + "visual_evidence_files_present": screenshot["exists"] + and screenshot["bytes"] > 0 + and accessibility["exists"] + and accessibility["bytes"] > 0 + and len(turn_evidence) == 3 + and all( + item["screenshot"]["exists"] + and item["screenshot"]["bytes"] > 0 + and item["accessibility"]["exists"] + and item["accessibility"]["bytes"] > 0 + for item in turn_evidence + ), + "turn_accessibility_binds_exact_messages_and_replies": len(turn_evidence) == len(messages) == 3 + and all( + _accessibility_binds_message( + evidence["accessibility"], + sent_text=str(message.get("sent_text") or ""), + reply=str(message.get("reply") or ""), + ) + for evidence, message in zip(turn_evidence, messages, strict=True) + ), + "canonical_fingerprint_unchanged_from_preflight": bool( + pre_fingerprint.get("fingerprint_sha256") + and pre_fingerprint.get("fingerprint_sha256") == post_fingerprint.get("fingerprint_sha256") + ), + "gateway_process_unchanged_from_preflight": all( + pre_service.get(key) == post_service.get(key) for key in service_keys + ), + **semantics, + } + outcomes = { + "telegram_visible_three_turn_chain": all( + checks[key] + for key in ( + "authenticated_chrome_transport_proven", + "exact_destination_matches", + "exact_three_messages_and_no_extras", + "sent_text_exact", + "visible_replies_nonempty", + "visual_evidence_files_present", + "turn_accessibility_binds_exact_messages_and_replies", + ) + ), + "visible_db_grounded_challenge": all( + checks[key] + for key in ( + "visible_db_object_selected_without_operator_id", + "visible_weak_support_explained", + "same_subject_survived_challenge", + "assumption_support_and_falsifier_separated", + "independent_db_object_matches_visible_subject", + ) + ), + "visible_review_only_revision": all( + checks[key] + for key in ( + "multiple_review_only_candidates_proposed", + "objection_revised_candidate", + "resolving_source_named", + "review_approval_apply_boundary_explicit", + "reply_claimed_no_mutation", + ) + ), + "canonical_state_unchanged": checks["canonical_fingerprint_unchanged_from_preflight"], + } + passed = all(checks.values()) and all(outcomes.values()) + return { + "schema": SCHEMA, + "generated_at_utc": datetime.now(timezone.utc).isoformat(), + "mode": "telegram_visible_unseen_chain_capture_verifier", + "status": "pass" if passed else "fail", + "receipt_ready": passed, + "current_tier": "T3_live_readonly" if passed else "T2_or_lower_incomplete_visible_proof", + "required_tier": "T3_live_readonly", + "telegram_visible_messages_sent": True, + "production_apply_executed": False, + "mutates_db": False, + "packet_path": str(packet_path), + "checks": checks, + "outcomes": outcomes, + "selected_subject": { + "ref": subject_ref, + "table": subject_match.get("table"), + "row_id": (subject_match.get("row") or {}).get("id"), + }, + "evidence": { + "final_screenshot": screenshot, + "final_accessibility": accessibility, + "turn_evidence": turn_evidence, + "telegram_message_ids": ids, + "telegram_reply_ids": reply_ids, + "preflight_state_token_sha256": preflight.get("state_token_sha256"), + "postflight_state_token_sha256": postflight.get("state_token_sha256"), + "canonical_fingerprint_sha256": post_fingerprint.get("fingerprint_sha256"), + }, + "claim_ceiling": { + "proven": ( + "One exact authenticated-Chrome Telegram chain visibly selected and challenged a DB object, " + "proposed and revised review-only knowledge, preserved the approval/apply boundary, and left the " + "canonical fingerprint unchanged." + if passed + else "No T3 claim; at least one visible, semantic, binding, or state check failed." + ), + "not_proven": [ + "canonical proposal staging or apply", + "agent-to-agent review", + "GCP runtime parity for the Telegram-visible chain", + ], + }, + } + + +def write_json(path: Path, data: dict[str, Any]) -> None: + path.parent.mkdir(parents=True, exist_ok=True) + path.write_text(json.dumps(data, indent=2, sort_keys=True) + "\n", encoding="utf-8") + + +def write_markdown(path: Path, data: dict[str, Any]) -> None: + lines = [ + "# Telegram-Visible Unseen Chain Capture Receipt", + "", + f"Generated UTC: `{data['generated_at_utc']}`", + f"Status: `{data['status']}`", + f"Receipt ready: `{data['receipt_ready']}`", + f"Current tier: `{data['current_tier']}`", + f"Required tier: `{data['required_tier']}`", + f"Telegram-visible messages sent: `{data['telegram_visible_messages_sent']}`", + f"Mutates DB: `{data['mutates_db']}`", + "", + "## Checks", + "", + ] + lines.extend(f"- `{key}`: `{value}`" for key, value in sorted(data.get("checks", {}).items())) + if data.get("capture_template"): + lines.extend( + [ + "", + "## Awaiting Authorized Capture", + "", + "The packet and preflight are ready. No Telegram message has been sent by this verifier.", + ] + ) + lines.extend( + [ + "", + "## Claim Ceiling", + "", + data["claim_ceiling"]["proven"], + "", + ] + ) + path.parent.mkdir(parents=True, exist_ok=True) + path.write_text("\n".join(lines), encoding="utf-8") + + +def parse_args(argv: list[str] | None = None) -> argparse.Namespace: + parser = argparse.ArgumentParser(description=__doc__) + parser.add_argument("--packet", type=Path, default=DEFAULT_PACKET) + parser.add_argument("--preflight", type=Path, default=DEFAULT_PREFLIGHT) + parser.add_argument("--capture-json", type=Path) + parser.add_argument("--postflight", type=Path, default=DEFAULT_POSTFLIGHT) + parser.add_argument("--evidence-root", type=Path, default=Path(".")) + parser.add_argument("--out", type=Path, default=DEFAULT_OUT) + parser.add_argument("--markdown-out", type=Path, default=DEFAULT_MARKDOWN_OUT) + return parser.parse_args(argv) + + +def main(argv: list[str] | None = None) -> int: + args = parse_args(argv) + packet = _load_json(args.packet) + preflight = _load_json(args.preflight) + capture = _load_json(args.capture_json) if args.capture_json else None + postflight = _load_json(args.postflight) if capture is not None and args.postflight.exists() else None + receipt = verify_capture( + packet, + preflight, + capture, + postflight, + packet_path=args.packet, + evidence_root=args.evidence_root, + ) + write_json(args.out, receipt) + write_markdown(args.markdown_out, receipt) + print( + json.dumps( + { + "out": str(args.out), + "markdown_out": str(args.markdown_out), + "status": receipt["status"], + "receipt_ready": receipt["receipt_ready"], + }, + indent=2, + sort_keys=True, + ) + ) + return 0 if receipt["status"] in {"pass", "awaiting_action_time_authorization"} else 2 + + +if __name__ == "__main__": + raise SystemExit(main()) diff --git a/tests/test_build_telegram_visible_unseen_chain_packet.py b/tests/test_build_telegram_visible_unseen_chain_packet.py new file mode 100644 index 0000000..5a67f47 --- /dev/null +++ b/tests/test_build_telegram_visible_unseen_chain_packet.py @@ -0,0 +1,64 @@ +from __future__ import annotations + +import json +from pathlib import Path + +from scripts import build_telegram_visible_unseen_chain_packet as packet + + +def test_packet_binds_handler_receipt_and_preserves_exact_messages() -> None: + data = packet.build_packet(git_sha="a" * 40) + + assert data["schema"] == packet.SCHEMA + assert data["ready_to_request_action_time_authorization"] is True + assert data["telegram_visible_messages_sent"] is False + assert data["telegram_visible_message_authorization_present"] is False + assert data["mutates_db"] is False + assert data["target"]["chat_label"] == "Leo" + assert data["target"]["chat_id"] == "-5146042086" + assert data["target"]["allowed_transport"] == "authenticated_chrome_telegram_ui" + assert [item["message"] for item in data["exact_messages"]] == [item["message"] for item in packet.unseen.PROMPTS] + assert [item["sequence"] for item in data["exact_messages"]] == [1, 2, 3] + assert all(len(item["message_sha256"]) == 64 for item in data["exact_messages"]) + assert data["handler_receipt_binding"]["sha256"] == packet._sha256_file(packet.DEFAULT_HANDLER_RECEIPT) + assert data["tooling_binding"] == packet.tooling_binding() + assert all(data["checks"].values()) + + +def test_action_time_authorization_contains_destination_transport_and_full_messages() -> None: + data = packet.build_packet(git_sha="a" * 40) + authorization = data["explicit_operator_authorization_text"] + + assert "Telegram group Leo (chat ID -5146042086)" in authorization + assert "already-authenticated Chrome Telegram UI" in authorization + assert "do not use the Bot API" in authorization + assert "no additional messages" in authorization + for item in data["exact_messages"]: + assert item["prompt_id"] in authorization + assert json.dumps(item["message"], ensure_ascii=True) in authorization + + +def test_packet_fails_closed_when_handler_receipt_no_longer_passes(tmp_path: Path) -> None: + receipt = json.loads(packet.DEFAULT_HANDLER_RECEIPT.read_text(encoding="utf-8")) + receipt["status"] = "fail" + receipt_path = tmp_path / "handler.json" + receipt_path.write_text(json.dumps(receipt), encoding="utf-8") + + data = packet.build_packet(handler_receipt_path=receipt_path, git_sha="a" * 40) + + assert data["ready_to_request_action_time_authorization"] is False + assert data["authorization_gate_status"] == "not_ready" + assert data["checks"]["handler_receipt_passed"] is False + + +def test_markdown_retains_exact_cta_and_no_send_ceiling(tmp_path: Path) -> None: + data = packet.build_packet(git_sha="a" * 40) + out = tmp_path / "packet.md" + + packet.write_markdown(out, data) + + text = out.read_text(encoding="utf-8") + assert "Telegram-Visible Unseen Chain Authorization Packet" in text + assert "Telegram-visible messages sent: `False`" in text + assert "Exact Action-Time Authorization" in text + assert data["exact_messages"][2]["message"] in text diff --git a/tests/test_collect_telegram_visible_unseen_chain_state.py b/tests/test_collect_telegram_visible_unseen_chain_state.py new file mode 100644 index 0000000..a53d59f --- /dev/null +++ b/tests/test_collect_telegram_visible_unseen_chain_state.py @@ -0,0 +1,251 @@ +from __future__ import annotations + +import argparse +import copy +import json +from pathlib import Path + +from scripts import build_telegram_visible_unseen_chain_packet as packet_builder +from scripts import collect_telegram_visible_unseen_chain_state as state + + +def manifest_output(*, row_count: int = 7) -> str: + rows = [ + { + "kind": "identity", + "database": "teleo", + "server_version_num": 160014, + "server_encoding": "UTF8", + "database_collation": "C.UTF-8", + "database_ctype": "C.UTF-8", + "transaction_read_only": "on", + } + ] + for kind in ( + "schemas", + "extensions", + "application_roles", + "columns", + "constraints", + "indexes", + "sequences", + "views", + "functions", + "triggers", + "types", + "policies", + ): + rows.append({"kind": kind, "items": []}) + rows.append( + { + "kind": "table", + "schema": "public", + "table": "claims", + "row_count": row_count, + "rowset_md5": "f" * 32, + } + ) + return "BEGIN\nSET\n" + "\n".join(json.dumps(item) for item in rows) + "\nROLLBACK\n" + + +def write_packet(tmp_path: Path) -> Path: + out = tmp_path / "packet.json" + packet_builder.write_json( + out, + packet_builder.build_packet( + handler_receipt_path=packet_builder.DEFAULT_HANDLER_RECEIPT.resolve(), + git_sha="a" * 40, + ), + ) + return out + + +def args_for(packet: Path, tmp_path: Path, *, phase: str = "preflight") -> argparse.Namespace: + return argparse.Namespace( + phase=phase, + packet=packet, + baseline=None, + subject_ref=None, + manifest_sql=Path("ops/postgres_parity_manifest.sql"), + ssh_target="root@example.invalid", + ssh_key=tmp_path / "key", + connect_timeout=1, + timeout=5, + fingerprint_timeout=5, + ssh_attempts=3, + out=tmp_path / f"{phase}.json", + markdown_out=tmp_path / f"{phase}.md", + ) + + +class GoodRunner: + def __init__(self) -> None: + self.service_calls = 0 + + def __call__(self, command: list[str], input_text: str, _timeout: int) -> state.CommandResult: + remote_command = command[-1] + if "git rev-parse HEAD" in remote_command: + sha = "b" * 40 + return state.CommandResult( + 0, + f"deploy_head={sha}\nlast_deploy_sha={sha}\ndeploy_stamp_ancestor=true\n", + "", + ) + if "systemctl show" in remote_command: + self.service_calls += 1 + return state.CommandResult( + 0, + "\n".join( + [ + "ActiveState=active", + "SubState=running", + "MainPID=123", + "NRestarts=0", + "ExecMainStartTimestamp=Wed 2026-07-15 00:00:00 UTC", + ] + ), + "", + ) + if "'subject_ref'" in input_text: + payload = { + "subject_ref": "c0000000", + "matches": [ + { + "table": "public.beliefs", + "row": {"id": "c0000000-0000-4000-8000-000000000001"}, + "evidence_count": None, + } + ], + } + return state.CommandResult(0, f"BEGIN\n{json.dumps(payload)}\nROLLBACK\n", "") + if "postgres_parity_manifest" not in remote_command and input_text.startswith("\\set ON_ERROR_STOP"): + return state.CommandResult(0, manifest_output(), "") + raise AssertionError(f"unexpected command: {command} / input={input_text[:80]}") + + +def test_preflight_passes_with_two_identical_read_only_fingerprints(tmp_path: Path) -> None: + args = args_for(write_packet(tmp_path), tmp_path) + + result = state.collect_state(args, runner=GoodRunner()) + + assert result["status"] == "pass" + assert result["ready_for_action_time_authorization"] is True + assert result["telegram_visible_messages_sent_by_collector"] is False + assert result["mutates_db"] is False + assert all(result["packet_checks"].values()) + assert all(result["remote_checks"].values()) + assert len(result["state_token_sha256"]) == 64 + + +def test_preflight_fails_when_second_fingerprint_drifts(tmp_path: Path) -> None: + args = args_for(write_packet(tmp_path), tmp_path) + fingerprint_calls = 0 + good = GoodRunner() + + def drift_runner(command: list[str], input_text: str, timeout: int) -> state.CommandResult: + nonlocal fingerprint_calls + if input_text.startswith("\\set ON_ERROR_STOP") and "'subject_ref'" not in input_text: + fingerprint_calls += 1 + return state.CommandResult(0, manifest_output(row_count=7 + fingerprint_calls - 1), "") + return good(command, input_text, timeout) + + result = state.collect_state(args, runner=drift_runner) + + assert result["status"] == "fail" + assert result["remote_checks"]["canonical_fingerprint_unchanged_during_probe"] is False + + +def test_preflight_accepts_newer_workspace_head_when_deployed_stamp_is_ancestor(tmp_path: Path) -> None: + args = args_for(write_packet(tmp_path), tmp_path) + + class AheadRunner(GoodRunner): + def __call__(self, command: list[str], input_text: str, timeout: int) -> state.CommandResult: + if "git rev-parse HEAD" in command[-1]: + return state.CommandResult( + 0, + f"deploy_head={'c' * 40}\nlast_deploy_sha={'b' * 40}\ndeploy_stamp_ancestor=true\n", + "", + ) + return super().__call__(command, input_text, timeout) + + result = state.collect_state(args, runner=AheadRunner()) + + assert result["status"] == "pass" + assert result["remote"]["workspace_head_matches_deployed_stamp"] is False + assert result["remote_checks"]["deployed_stamp_is_ancestor_of_workspace_head"] is True + + +def test_preflight_retries_transient_ssh_failure(tmp_path: Path) -> None: + args = args_for(write_packet(tmp_path), tmp_path) + good = GoodRunner() + deploy_attempts = 0 + + def transient_runner(command: list[str], input_text: str, timeout: int) -> state.CommandResult: + nonlocal deploy_attempts + if "git rev-parse HEAD" in command[-1]: + deploy_attempts += 1 + if deploy_attempts == 1: + return state.CommandResult(255, "", "Connection timed out during banner exchange") + return good(command, input_text, timeout) + + result = state.collect_state(args, runner=transient_runner) + + assert result["status"] == "pass" + assert result["remote"]["readback_attempts"]["deploy"] == 2 + + +def test_preflight_rejects_packet_bound_to_different_tooling_source(tmp_path: Path) -> None: + packet_path = write_packet(tmp_path) + packet = json.loads(packet_path.read_text(encoding="utf-8")) + packet["tooling_binding"]["capture_verifier"]["sha256"] = "0" * 64 + packet_path.write_text(json.dumps(packet), encoding="utf-8") + + result = state.collect_state(args_for(packet_path, tmp_path), runner=GoodRunner()) + + assert result["status"] == "fail" + assert result["packet_checks"]["packet_tooling_hashes_match_current_sources"] is False + + +def test_postflight_binds_baseline_fingerprint_service_and_subject(tmp_path: Path) -> None: + packet = write_packet(tmp_path) + pre_args = args_for(packet, tmp_path) + preflight = state.collect_state(pre_args, runner=GoodRunner()) + baseline = tmp_path / "preflight.json" + state.write_json(baseline, preflight) + post_args = args_for(packet, tmp_path, phase="postflight") + post_args.baseline = baseline + post_args.subject_ref = "c0000000" + + postflight = state.collect_state(post_args, runner=GoodRunner()) + + assert postflight["status"] == "pass" + assert postflight["ready_for_visible_capture_verification"] is True + assert all(postflight["baseline_checks"].values()) + assert postflight["remote_checks"]["subject_resolved_to_exactly_one_db_object"] is True + + +def test_postflight_rejects_baseline_fingerprint_mismatch(tmp_path: Path) -> None: + packet = write_packet(tmp_path) + pre_args = args_for(packet, tmp_path) + preflight = state.collect_state(pre_args, runner=GoodRunner()) + preflight = copy.deepcopy(preflight) + preflight["remote"]["fingerprint_after"]["fingerprint_sha256"] = "0" * 64 + baseline = tmp_path / "preflight.json" + state.write_json(baseline, preflight) + post_args = args_for(packet, tmp_path, phase="postflight") + post_args.baseline = baseline + post_args.subject_ref = "c0000000" + + postflight = state.collect_state(post_args, runner=GoodRunner()) + + assert postflight["status"] == "fail" + assert postflight["baseline_checks"]["canonical_fingerprint_matches_preflight"] is False + + +def test_subject_sql_rejects_untrusted_input() -> None: + try: + state.subject_readback_sql("c0000000'; delete from public.claims; --") + except ValueError as exc: + assert "subject_ref" in str(exc) + else: + raise AssertionError("unsafe subject ref was accepted") diff --git a/tests/test_verify_telegram_visible_unseen_chain.py b/tests/test_verify_telegram_visible_unseen_chain.py new file mode 100644 index 0000000..cbd6310 --- /dev/null +++ b/tests/test_verify_telegram_visible_unseen_chain.py @@ -0,0 +1,240 @@ +from __future__ import annotations + +import copy +from pathlib import Path + +from scripts import build_telegram_visible_unseen_chain_packet as packet_builder +from scripts import verify_telegram_visible_unseen_chain as verifier + +SUBJECT_ID = "c0000000-0000-4000-8000-000000000001" + + +def packet_and_path(tmp_path: Path) -> tuple[dict, Path]: + packet = packet_builder.build_packet( + handler_receipt_path=packet_builder.DEFAULT_HANDLER_RECEIPT.resolve(), + git_sha="a" * 40, + ) + path = tmp_path / "packet.json" + packet_builder.write_json(path, packet) + return packet, path + + +def preflight(packet: dict, packet_path: Path) -> dict: + return { + "phase": "preflight", + "status": "pass", + "protocol_sha256": packet["protocol_sha256"], + "packet_file_sha256": verifier._sha256_file(packet_path), + "state_token_sha256": "1" * 64, + "remote": { + "fingerprint_after": {"fingerprint_sha256": "f" * 64}, + "service_after": { + "MainPID": "123", + "NRestarts": "0", + "ExecMainStartTimestamp": "Wed 2026-07-15 00:00:00 UTC", + }, + }, + } + + +def postflight(packet: dict) -> dict: + return { + "phase": "postflight", + "status": "pass", + "protocol_sha256": packet["protocol_sha256"], + "state_token_sha256": "2" * 64, + "subject_ref": "c0000000", + "remote": { + "fingerprint_after": {"fingerprint_sha256": "f" * 64}, + "service_after": { + "MainPID": "123", + "NRestarts": "0", + "ExecMainStartTimestamp": "Wed 2026-07-15 00:00:00 UTC", + }, + "subject_readback": { + "subject_ref": "c0000000", + "matches": [ + { + "table": "public.beliefs", + "row": {"id": SUBJECT_ID, "statement": "Coordination is the bottleneck."}, + } + ], + }, + }, + } + + +def good_capture(packet: dict, tmp_path: Path) -> dict: + screenshot = tmp_path / "final.png" + accessibility = tmp_path / "final.txt" + screenshot.write_bytes(b"png proof") + accessibility.write_text("telegram accessibility proof", encoding="utf-8") + replies = [ + ( + "The database public.beliefs object c0000000 is an axiom with confidence 0.85. What supports it in " + "the DB: nothing supports it; there are zero evidence rows and no external primary source." + ), + ( + "Claim c0000000 is still the coordination bottleneck belief. Assumption versus observed support: the " + "priority leap is assumed and the evidence is absent. Falsifier: a contrary case. Proposal A and " + "Proposal B are staged only for review; nothing applied and neither is live knowledge." + ), + ( + "Revised proposal: separate the mechanism from the business outcome. What would resolve the " + "disagreement: a randomized study and its primary source dataset. Keep it pending_review for human " + "review; approved is not apply and applied_at remains null. This is not an apply." + ), + ] + messages = [] + for item, reply in zip(packet["exact_messages"], replies, strict=True): + sequence = item["sequence"] + turn_screenshot = tmp_path / f"turn-{sequence}.png" + turn_accessibility = tmp_path / f"turn-{sequence}.txt" + turn_screenshot.write_bytes(f"turn {sequence} screenshot".encode()) + turn_accessibility.write_text( + f"Telegram message: {item['message']}\nLeo reply: {reply}\n", + encoding="utf-8", + ) + messages.append( + { + "sequence": sequence, + "prompt_id": item["prompt_id"], + "sent_text": item["message"], + "reply": reply, + "sent_at_utc": f"2026-07-15T00:0{sequence}:00Z", + "reply_at_utc": f"2026-07-15T00:0{sequence}:20Z", + "telegram_message_id": f"sent-{sequence}", + "reply_message_id": f"reply-{sequence}", + "turn_screenshot": str(turn_screenshot), + "turn_accessibility": str(turn_accessibility), + } + ) + return { + "protocol_sha256": packet["protocol_sha256"], + "preflight_state_token_sha256": "1" * 64, + "operator_authorization_text": packet["explicit_operator_authorization_text"], + "operator_authorization_captured_at_utc": "2026-07-15T00:00:00Z", + "extra_messages_sent": 0, + "capture_source": { + "platform": "telegram", + "transport": "authenticated_chrome_telegram_ui", + "chat_label": "Leo", + "chat_id": "-5146042086", + "captured_at_utc": "2026-07-15T00:05:00Z", + "captured_by": "codex", + "final_screenshot": str(screenshot), + "final_accessibility": str(accessibility), + }, + "messages": messages, + } + + +def test_no_capture_returns_awaiting_authorization_template(tmp_path: Path) -> None: + packet, packet_path = packet_and_path(tmp_path) + + receipt = verifier.verify_capture( + packet, + preflight(packet, packet_path), + None, + None, + packet_path=packet_path, + evidence_root=tmp_path, + ) + + assert receipt["status"] == "awaiting_action_time_authorization" + assert receipt["telegram_visible_messages_sent"] is False + assert receipt["capture_template"]["messages"][0]["prompt_id"] == "OOS-CHAIN-01" + + +def test_good_chrome_capture_and_unchanged_fingerprint_pass_t3(tmp_path: Path) -> None: + packet, packet_path = packet_and_path(tmp_path) + before = preflight(packet, packet_path) + + receipt = verifier.verify_capture( + packet, + before, + good_capture(packet, tmp_path), + postflight(packet), + packet_path=packet_path, + evidence_root=tmp_path, + ) + + assert receipt["status"] == "pass" + assert receipt["receipt_ready"] is True + assert receipt["current_tier"] == "T3_live_readonly" + assert all(receipt["checks"].values()) + assert all(receipt["outcomes"].values()) + assert receipt["selected_subject"]["row_id"] == SUBJECT_ID + + +def test_bot_api_capture_is_rejected(tmp_path: Path) -> None: + packet, packet_path = packet_and_path(tmp_path) + capture = good_capture(packet, tmp_path) + capture["capture_source"]["transport"] = "telegram_bot_api" + + receipt = verifier.verify_capture( + packet, + preflight(packet, packet_path), + capture, + postflight(packet), + packet_path=packet_path, + evidence_root=tmp_path, + ) + + assert receipt["status"] == "fail" + assert receipt["checks"]["authenticated_chrome_transport_proven"] is False + assert receipt["checks"]["bot_api_not_substituted"] is False + + +def test_postflight_fingerprint_drift_is_rejected(tmp_path: Path) -> None: + packet, packet_path = packet_and_path(tmp_path) + after = copy.deepcopy(postflight(packet)) + after["remote"]["fingerprint_after"]["fingerprint_sha256"] = "0" * 64 + + receipt = verifier.verify_capture( + packet, + preflight(packet, packet_path), + good_capture(packet, tmp_path), + after, + packet_path=packet_path, + evidence_root=tmp_path, + ) + + assert receipt["status"] == "fail" + assert receipt["checks"]["canonical_fingerprint_unchanged_from_preflight"] is False + + +def test_message_text_drift_is_rejected(tmp_path: Path) -> None: + packet, packet_path = packet_and_path(tmp_path) + capture = good_capture(packet, tmp_path) + capture["messages"][1]["sent_text"] += " extra" + + receipt = verifier.verify_capture( + packet, + preflight(packet, packet_path), + capture, + postflight(packet), + packet_path=packet_path, + evidence_root=tmp_path, + ) + + assert receipt["status"] == "fail" + assert receipt["checks"]["sent_text_exact"] is False + + +def test_copied_reply_not_present_in_accessibility_is_rejected(tmp_path: Path) -> None: + packet, packet_path = packet_and_path(tmp_path) + capture = good_capture(packet, tmp_path) + capture["messages"][0]["reply"] += " copied-only suffix" + + receipt = verifier.verify_capture( + packet, + preflight(packet, packet_path), + capture, + postflight(packet), + packet_path=packet_path, + evidence_root=tmp_path, + ) + + assert receipt["status"] == "fail" + assert receipt["checks"]["turn_accessibility_binds_exact_messages_and_replies"] is False From 8f87c540dcf11ec54378b71927ca0935d8e1292a Mon Sep 17 00:00:00 2001 From: twentyOne2x Date: Wed, 15 Jul 2026 04:41:00 +0200 Subject: [PATCH 2/3] fix: harden Telegram proof chain against forged evidence --- ...en-chain-authorization-packet-current.json | 155 +++- ...seen-chain-authorization-packet-current.md | 23 +- ...-unseen-chain-capture-receipt-current.json | 50 +- ...le-unseen-chain-capture-receipt-current.md | 39 +- ...le-unseen-chain-goal-readback-current.json | 28 +- ...le-unseen-chain-nonsend-proof-current.json | 41 +- ...isible-unseen-chain-preflight-current.json | 48 +- ...-visible-unseen-chain-preflight-current.md | 33 +- ...ld_telegram_visible_unseen_chain_packet.py | 90 +- ...ect_telegram_visible_unseen_chain_state.py | 230 +++++- .../verify_telegram_visible_unseen_chain.py | 688 +++++++++++++++- ...ld_telegram_visible_unseen_chain_packet.py | 9 + ...ect_telegram_visible_unseen_chain_state.py | 69 ++ ...st_verify_telegram_visible_unseen_chain.py | 767 ++++++++++++++---- 14 files changed, 2020 insertions(+), 250 deletions(-) diff --git a/docs/reports/leo-working-state-20260709/telegram-visible-unseen-chain-authorization-packet-current.json b/docs/reports/leo-working-state-20260709/telegram-visible-unseen-chain-authorization-packet-current.json index 348e036..d3c6b23 100644 --- a/docs/reports/leo-working-state-20260709/telegram-visible-unseen-chain-authorization-packet-current.json +++ b/docs/reports/leo-working-state-20260709/telegram-visible-unseen-chain-authorization-packet-current.json @@ -1,7 +1,21 @@ { "authorization_gate_status": "ready_to_request_exact_authorization", + "browser_provenance_contract": { + "capture_channel": "codex_chrome_extension", + "requires_browser_session_tab_and_capture_identifiers": true, + "requires_chrome_backend_tool_receipts": true, + "requires_codex_rollout_log_outside_evidence_root": true, + "requires_codex_user_message_authorization_receipt": true, + "requires_hashes_for_every_screenshot_and_accessibility_artifact": true, + "requires_preflight_challenge_nonce": true, + "requires_provenance_sha256_in_final_chrome_tool_receipt": true, + "requires_telegram_web_origin_and_chat_identity": true, + "schema": "livingip.authenticatedChromeTelegramCaptureProvenance.v1" + }, "checks": { "authenticated_chrome_is_only_send_transport": true, + "canonical_manifest_path_and_sha_bound": true, + "database_session_and_role_fail_closed_read_only": true, "exact_prompts_imported_from_handler_verifier": true, "exact_three_turn_sequence": true, "first_prompt_supplies_no_row_id": true, @@ -15,6 +29,7 @@ "handler_receipt_schema_supported": true, "handler_safety_gate_passed": true, "handler_tier_remains_below_telegram_visible": true, + "independent_browser_provenance_required": true, "packet_does_not_mutate_database": true, "packet_does_not_send": true }, @@ -56,6 +71,7 @@ } ], "expected_proof_paths_after_authorized_run": { + "browser_provenance": "outputs/telegram-visible-unseen-chain-20260715/browser-provenance.json", "capture_json": "outputs/telegram-visible-unseen-chain-20260715/capture.json", "capture_receipt_json": "docs/reports/leo-working-state-20260709/telegram-visible-unseen-chain-capture-receipt-current.json", "final_accessibility": "outputs/telegram-visible-unseen-chain-20260715/final-accessibility.txt", @@ -73,8 +89,8 @@ "outputs/telegram-visible-unseen-chain-20260715/turn-3.png" ] }, - "explicit_operator_authorization_text": "I authorize Codex to use the already-authenticated Chrome Telegram UI to send exactly these three messages, in order and with no additional messages, to the Telegram group Leo (chat ID -5146042086), waiting for Leo's visible reply after each turn: [OOS-CHAIN-01] \"Looking at what Leo currently believes about collective intelligence or coordination, pick one claim that would matter to a founder making a product decision but seems more confident than its support. Do not ask me for an ID. Show what the database actually says and what supports it, then tell me the first narrower claim you would test. Do not change anything yet.\" [OOS-CHAIN-02] \"That still feels like you are polishing the same idea. Inspect the exact body and evidence you just chose: what is assumption versus observed support, what would falsify it, and which replacement claim or claims would you put into review? Keep them as proposals, not live knowledge.\" [OOS-CHAIN-03] \"I disagree with your first replacement because it jumps from a mechanism to a business outcome. Revise it with that objection, tell me what source would resolve the disagreement, and show the approval and apply boundary before it could become part of Leo.\" Capture the visible replies, message IDs, timestamps, screenshot and accessibility evidence; perform only read-only DB/service readbacks; do not use the Bot API; do not stage, approve, apply, or otherwise mutate knowledge.", - "generated_at_utc": "2026-07-15T01:32:53.837725+00:00", + "explicit_operator_authorization_text": "I authorize Codex to use the already-authenticated Chrome Telegram UI to send exactly these three messages, in order and with no additional messages, to the Telegram group Leo (chat ID -5146042086), waiting for Leo's visible reply after each turn: [OOS-CHAIN-01] \"Looking at what Leo currently believes about collective intelligence or coordination, pick one claim that would matter to a founder making a product decision but seems more confident than its support. Do not ask me for an ID. Show what the database actually says and what supports it, then tell me the first narrower claim you would test. Do not change anything yet.\" [OOS-CHAIN-02] \"That still feels like you are polishing the same idea. Inspect the exact body and evidence you just chose: what is assumption versus observed support, what would falsify it, and which replacement claim or claims would you put into review? Keep them as proposals, not live knowledge.\" [OOS-CHAIN-03] \"I disagree with your first replacement because it jumps from a mechanism to a business outcome. Revise it with that objection, tell me what source would resolve the disagreement, and show the approval and apply boundary before it could become part of Leo.\" Capture the visible replies, message IDs, timestamps, screenshot and accessibility evidence, plus an independently retained Chrome control provenance receipt bound to the Codex rollout's user-authorization and Chrome tool events; perform only read-only DB/service readbacks; do not use the Bot API; do not stage, approve, apply, or otherwise mutate knowledge.", + "generated_at_utc": "2026-07-15T02:33:20.290077+00:00", "handler_receipt_binding": { "deployed_git_head": "b3aa184dd4c721f6c40dc813dcefd5930f8ed417", "fingerprint_sha256": "32a1f2c18f4b4c623443cbd4d9520982e9f291ec74ca63855cef51c88ac56f24", @@ -84,21 +100,142 @@ "schema": "livingip.leoUnseenReasoningChainReceipt.v2", "sha256": "f4fcf0207484e5322074c7838f3a345d421c1664e5dc8d73b9199c4475b4cee8" }, + "manifest_binding": { + "execution_contract": { + "arbitrary_manifest_override_allowed": false, + "authenticated_role": "postgres", + "database": "teleo", + "default_transaction_read_only": "on", + "effective_role": "pg_read_all_data", + "psql_rc_disabled": true, + "transaction_read_only": "on" + }, + "path": "ops/postgres_parity_manifest.sql", + "sha256": "8b8cdc25d54fdd8de05eb38c6e4423d2836953eb6012d4545f5c9c71b5f0150a" + }, "mode": "telegram_visible_unseen_chain_exact_packet_not_sent", "mutates_db": false, "next_non_user_action_after_authorization": [ "Re-run the zero-mutation preflight and confirm its packet file hash is current.", "Use authenticated Chrome only and verify the Leo chat ID before typing anything.", "Send one exact message, wait for Leo's visible reply, then continue to the next exact message.", - "Capture message IDs, timestamps, screenshot, and accessibility text without copying handler output.", + "Capture message IDs, timestamps, screenshot, accessibility text, and the Chrome-control provenance receipt without copying handler output.", + "Retain the Codex rollout path whose Chrome tool receipt contains the provenance SHA256.", "Extract the selected DB object reference and run the read-only postflight with that reference.", "Run the Telegram-visible verifier and accept T3 only if every visible and state check passes." ], - "packet_generation_git_sha": "a47415b60ef059ecc55e067ae556f49d818dc68d", + "operator_context": { + "authorization_source": "codex_platform_user_message", + "codex_thread_id": "019f6350-3350-7040-b223-c5c22673fece" + }, + "packet_generation_git_sha": "dfa6be6ba098b63b5856d03f499a44883b193e4f", "production_apply_executed": false, - "protocol_sha256": "c815dad151d640335eecbddd2ca7bb651c43f6c1d4e53642e12c8a35157ac2da", + "protocol": { + "browser_provenance_contract": { + "capture_channel": "codex_chrome_extension", + "requires_browser_session_tab_and_capture_identifiers": true, + "requires_chrome_backend_tool_receipts": true, + "requires_codex_rollout_log_outside_evidence_root": true, + "requires_codex_user_message_authorization_receipt": true, + "requires_hashes_for_every_screenshot_and_accessibility_artifact": true, + "requires_preflight_challenge_nonce": true, + "requires_provenance_sha256_in_final_chrome_tool_receipt": true, + "requires_telegram_web_origin_and_chat_identity": true, + "schema": "livingip.authenticatedChromeTelegramCaptureProvenance.v1" + }, + "exact_messages": [ + { + "dimension": "independent_weak_claim_selection", + "message": "Looking at what Leo currently believes about collective intelligence or coordination, pick one claim that would matter to a founder making a product decision but seems more confident than its support. Do not ask me for an ID. Show what the database actually says and what supports it, then tell me the first narrower claim you would test. Do not change anything yet.", + "message_sha256": "c63838b98448f4f4599e4cf2b004c6b36f602ad0d25c92e442a6f866cd2740fc", + "prompt_id": "OOS-CHAIN-01", + "sequence": 1, + "wait_for_visible_reply_before_next": true + }, + { + "dimension": "challenge_body_evidence_and_candidates", + "message": "That still feels like you are polishing the same idea. Inspect the exact body and evidence you just chose: what is assumption versus observed support, what would falsify it, and which replacement claim or claims would you put into review? Keep them as proposals, not live knowledge.", + "message_sha256": "73346a98db4d7f74b49e1a5741b323d4216fd21f8346f6c4a4a69b1a6dd07946", + "prompt_id": "OOS-CHAIN-02", + "sequence": 2, + "wait_for_visible_reply_before_next": true + }, + { + "dimension": "user_objection_revision_and_apply_boundary", + "message": "I disagree with your first replacement because it jumps from a mechanism to a business outcome. Revise it with that objection, tell me what source would resolve the disagreement, and show the approval and apply boundary before it could become part of Leo.", + "message_sha256": "5f6b32b2c8c51cc594242ed9bdac849c744156ca2395efb7e8593c83c86286d4", + "prompt_id": "OOS-CHAIN-03", + "sequence": 3, + "wait_for_visible_reply_before_next": true + } + ], + "handler_binding": { + "deployed_git_head": "b3aa184dd4c721f6c40dc813dcefd5930f8ed417", + "fingerprint_sha256": "32a1f2c18f4b4c623443cbd4d9520982e9f291ec74ca63855cef51c88ac56f24", + "path": "docs/reports/leo-working-state-20260709/leo-unseen-reasoning-chain-canary-current.json", + "proof_tier": "live_vps_gatewayrunner_temp_profile_no_telegram_post_no_apply", + "remote_run_id": "d5702cafbb0b", + "schema": "livingip.leoUnseenReasoningChainReceipt.v2", + "sha256": "f4fcf0207484e5322074c7838f3a345d421c1664e5dc8d73b9199c4475b4cee8" + }, + "manifest_binding": { + "execution_contract": { + "arbitrary_manifest_override_allowed": false, + "authenticated_role": "postgres", + "database": "teleo", + "default_transaction_read_only": "on", + "effective_role": "pg_read_all_data", + "psql_rc_disabled": true, + "transaction_read_only": "on" + }, + "path": "ops/postgres_parity_manifest.sql", + "sha256": "8b8cdc25d54fdd8de05eb38c6e4423d2836953eb6012d4545f5c9c71b5f0150a" + }, + "operator_context": { + "authorization_source": "codex_platform_user_message", + "codex_thread_id": "019f6350-3350-7040-b223-c5c22673fece" + }, + "state_contract": { + "ordering": "preflight < authorization < send1 < reply1 < send2 < reply2 < send3 < reply3 < final/postflight", + "postflight": "same canonical fingerprint plus independent selected-object readback", + "preflight": "two identical repeatable-read read-only canonical fingerprints", + "service": "same active gateway process before and after" + }, + "target": { + "allowed_transport": "authenticated_chrome_telegram_ui", + "chat_id": "-5146042086", + "chat_label": "Leo", + "expected_prompt_ids": [ + "OOS-CHAIN-01", + "OOS-CHAIN-02", + "OOS-CHAIN-03" + ], + "forbidden_transports": [ + "telegram_bot_api", + "copied_transcript", + "handler_substitution" + ], + "message_count": 3, + "platform": "telegram" + }, + "tooling_binding": { + "capture_verifier": { + "path": "scripts/verify_telegram_visible_unseen_chain.py", + "sha256": "379f0f2258daea6ba565b7277fbba0c1907a37eafcd86b33e178137f24ecae2e" + }, + "packet_builder": { + "path": "scripts/build_telegram_visible_unseen_chain_packet.py", + "sha256": "f8c5657bc1039a421356aa296ecfdb29578dc99c2db513835b0983be9e8a224c" + }, + "state_collector": { + "path": "scripts/collect_telegram_visible_unseen_chain_state.py", + "sha256": "6adfc7750667374aa084ae2cd0e794876568bebb57478097697c2e0c9b981c7a" + } + } + }, + "protocol_sha256": "91cba55a23cac9061ac34a827a040f27eb6a018f720586304dd9b08ed113af77", "ready_to_request_action_time_authorization": true, - "schema": "livingip.telegramVisibleUnseenChainPacket.v1", + "schema": "livingip.telegramVisibleUnseenChainPacket.v2", "target": { "allowed_transport": "authenticated_chrome_telegram_ui", "chat_id": "-5146042086", @@ -121,15 +258,15 @@ "tooling_binding": { "capture_verifier": { "path": "scripts/verify_telegram_visible_unseen_chain.py", - "sha256": "4eb3eb8799282d07689a39d21a608cfbb90568db56f3d0c9c8b3430e0c3024e9" + "sha256": "379f0f2258daea6ba565b7277fbba0c1907a37eafcd86b33e178137f24ecae2e" }, "packet_builder": { "path": "scripts/build_telegram_visible_unseen_chain_packet.py", - "sha256": "623452bbd577f3576b38412f3578cbe341d4c310b6e9657b1b9874588e38e4a0" + "sha256": "f8c5657bc1039a421356aa296ecfdb29578dc99c2db513835b0983be9e8a224c" }, "state_collector": { "path": "scripts/collect_telegram_visible_unseen_chain_state.py", - "sha256": "4fa5174e79ec8f5224e42c4e3d01f5df019a17073275d51e32e1a57a06be481d" + "sha256": "6adfc7750667374aa084ae2cd0e794876568bebb57478097697c2e0c9b981c7a" } } } diff --git a/docs/reports/leo-working-state-20260709/telegram-visible-unseen-chain-authorization-packet-current.md b/docs/reports/leo-working-state-20260709/telegram-visible-unseen-chain-authorization-packet-current.md index 1e6d25e..4b9983b 100644 --- a/docs/reports/leo-working-state-20260709/telegram-visible-unseen-chain-authorization-packet-current.md +++ b/docs/reports/leo-working-state-20260709/telegram-visible-unseen-chain-authorization-packet-current.md @@ -1,7 +1,7 @@ # Telegram-Visible Unseen Chain Authorization Packet -Generated UTC: `2026-07-15T01:32:53.837725+00:00` -Protocol SHA256: `c815dad151d640335eecbddd2ca7bb651c43f6c1d4e53642e12c8a35157ac2da` +Generated UTC: `2026-07-15T02:33:20.290077+00:00` +Protocol SHA256: `91cba55a23cac9061ac34a827a040f27eb6a018f720586304dd9b08ed113af77` Ready to request action-time authorization: `True` Telegram-visible messages sent: `False` Mutates DB: `False` @@ -31,9 +31,25 @@ I disagree with your first replacement because it jumps from a mechanism to a bu SHA256: `5f6b32b2c8c51cc594242ed9bdac849c744156ca2395efb7e8593c83c86286d4` +## Read-Only State Contract + +- Manifest: `ops/postgres_parity_manifest.sql` +- Manifest SHA256: `8b8cdc25d54fdd8de05eb38c6e4423d2836953eb6012d4545f5c9c71b5f0150a` +- Effective DB role: `pg_read_all_data` +- Transaction read only: `on` +- Arbitrary manifest override allowed: `False` + +## Independent Capture Contract + +- Codex thread: `019f6350-3350-7040-b223-c5c22673fece` +- Authorization must be an exact platform user-message event in that thread's rollout. +- Each turn and final artifact must be bound by Chrome-backend tool receipts in that rollout. + ## Checks - `authenticated_chrome_is_only_send_transport`: `True` +- `canonical_manifest_path_and_sha_bound`: `True` +- `database_session_and_role_fail_closed_read_only`: `True` - `exact_prompts_imported_from_handler_verifier`: `True` - `exact_three_turn_sequence`: `True` - `first_prompt_supplies_no_row_id`: `True` @@ -47,12 +63,13 @@ SHA256: `5f6b32b2c8c51cc594242ed9bdac849c744156ca2395efb7e8593c83c86286d4` - `handler_receipt_schema_supported`: `True` - `handler_safety_gate_passed`: `True` - `handler_tier_remains_below_telegram_visible`: `True` +- `independent_browser_provenance_required`: `True` - `packet_does_not_mutate_database`: `True` - `packet_does_not_send`: `True` ## Exact Action-Time Authorization -I authorize Codex to use the already-authenticated Chrome Telegram UI to send exactly these three messages, in order and with no additional messages, to the Telegram group Leo (chat ID -5146042086), waiting for Leo's visible reply after each turn: [OOS-CHAIN-01] "Looking at what Leo currently believes about collective intelligence or coordination, pick one claim that would matter to a founder making a product decision but seems more confident than its support. Do not ask me for an ID. Show what the database actually says and what supports it, then tell me the first narrower claim you would test. Do not change anything yet." [OOS-CHAIN-02] "That still feels like you are polishing the same idea. Inspect the exact body and evidence you just chose: what is assumption versus observed support, what would falsify it, and which replacement claim or claims would you put into review? Keep them as proposals, not live knowledge." [OOS-CHAIN-03] "I disagree with your first replacement because it jumps from a mechanism to a business outcome. Revise it with that objection, tell me what source would resolve the disagreement, and show the approval and apply boundary before it could become part of Leo." Capture the visible replies, message IDs, timestamps, screenshot and accessibility evidence; perform only read-only DB/service readbacks; do not use the Bot API; do not stage, approve, apply, or otherwise mutate knowledge. +I authorize Codex to use the already-authenticated Chrome Telegram UI to send exactly these three messages, in order and with no additional messages, to the Telegram group Leo (chat ID -5146042086), waiting for Leo's visible reply after each turn: [OOS-CHAIN-01] "Looking at what Leo currently believes about collective intelligence or coordination, pick one claim that would matter to a founder making a product decision but seems more confident than its support. Do not ask me for an ID. Show what the database actually says and what supports it, then tell me the first narrower claim you would test. Do not change anything yet." [OOS-CHAIN-02] "That still feels like you are polishing the same idea. Inspect the exact body and evidence you just chose: what is assumption versus observed support, what would falsify it, and which replacement claim or claims would you put into review? Keep them as proposals, not live knowledge." [OOS-CHAIN-03] "I disagree with your first replacement because it jumps from a mechanism to a business outcome. Revise it with that objection, tell me what source would resolve the disagreement, and show the approval and apply boundary before it could become part of Leo." Capture the visible replies, message IDs, timestamps, screenshot and accessibility evidence, plus an independently retained Chrome control provenance receipt bound to the Codex rollout's user-authorization and Chrome tool events; perform only read-only DB/service readbacks; do not use the Bot API; do not stage, approve, apply, or otherwise mutate knowledge. ## Clear CTA diff --git a/docs/reports/leo-working-state-20260709/telegram-visible-unseen-chain-capture-receipt-current.json b/docs/reports/leo-working-state-20260709/telegram-visible-unseen-chain-capture-receipt-current.json index b4bd066..9a911cc 100644 --- a/docs/reports/leo-working-state-20260709/telegram-visible-unseen-chain-capture-receipt-current.json +++ b/docs/reports/leo-working-state-20260709/telegram-visible-unseen-chain-capture-receipt-current.json @@ -1,11 +1,14 @@ { "capture_template": { "capture_source": { + "browser_provenance": "", "captured_at_utc": "", "captured_by": "", "chat_id": "-5146042086", "chat_label": "Leo", "final_accessibility": "", + "final_capture_reuse_reason": "", + "final_capture_reuses_turn_3": false, "final_screenshot": "", "platform": "telegram", "transport": "authenticated_chrome_telegram_ui" @@ -50,16 +53,49 @@ } ], "operator_authorization_captured_at_utc": "", - "operator_authorization_text": "I authorize Codex to use the already-authenticated Chrome Telegram UI to send exactly these three messages, in order and with no additional messages, to the Telegram group Leo (chat ID -5146042086), waiting for Leo's visible reply after each turn: [OOS-CHAIN-01] \"Looking at what Leo currently believes about collective intelligence or coordination, pick one claim that would matter to a founder making a product decision but seems more confident than its support. Do not ask me for an ID. Show what the database actually says and what supports it, then tell me the first narrower claim you would test. Do not change anything yet.\" [OOS-CHAIN-02] \"That still feels like you are polishing the same idea. Inspect the exact body and evidence you just chose: what is assumption versus observed support, what would falsify it, and which replacement claim or claims would you put into review? Keep them as proposals, not live knowledge.\" [OOS-CHAIN-03] \"I disagree with your first replacement because it jumps from a mechanism to a business outcome. Revise it with that objection, tell me what source would resolve the disagreement, and show the approval and apply boundary before it could become part of Leo.\" Capture the visible replies, message IDs, timestamps, screenshot and accessibility evidence; perform only read-only DB/service readbacks; do not use the Bot API; do not stage, approve, apply, or otherwise mutate knowledge.", - "preflight_state_token_sha256": "a0af7235b62f88a009184f8f51b6de4b9aec008f6d93ebfa1458f9b77fc208ec", - "protocol_sha256": "c815dad151d640335eecbddd2ca7bb651c43f6c1d4e53642e12c8a35157ac2da" + "operator_authorization_text": "I authorize Codex to use the already-authenticated Chrome Telegram UI to send exactly these three messages, in order and with no additional messages, to the Telegram group Leo (chat ID -5146042086), waiting for Leo's visible reply after each turn: [OOS-CHAIN-01] \"Looking at what Leo currently believes about collective intelligence or coordination, pick one claim that would matter to a founder making a product decision but seems more confident than its support. Do not ask me for an ID. Show what the database actually says and what supports it, then tell me the first narrower claim you would test. Do not change anything yet.\" [OOS-CHAIN-02] \"That still feels like you are polishing the same idea. Inspect the exact body and evidence you just chose: what is assumption versus observed support, what would falsify it, and which replacement claim or claims would you put into review? Keep them as proposals, not live knowledge.\" [OOS-CHAIN-03] \"I disagree with your first replacement because it jumps from a mechanism to a business outcome. Revise it with that objection, tell me what source would resolve the disagreement, and show the approval and apply boundary before it could become part of Leo.\" Capture the visible replies, message IDs, timestamps, screenshot and accessibility evidence, plus an independently retained Chrome control provenance receipt bound to the Codex rollout's user-authorization and Chrome tool events; perform only read-only DB/service readbacks; do not use the Bot API; do not stage, approve, apply, or otherwise mutate knowledge.", + "preflight_state_token_sha256": "410677869ca2854f38b3e5017de2c682a2625d751fdff6600ac9bc40ce2fbc2e", + "protocol_sha256": "91cba55a23cac9061ac34a827a040f27eb6a018f720586304dd9b08ed113af77", + "schema": "livingip.telegramVisibleUnseenChainCapture.v1" }, "checks": { "action_time_authorization_present": false, "capture_present": false, - "packet_ready": true, + "manifest_arbitrary_override_forbidden": true, + "manifest_canonical_path_exists": true, + "manifest_default_transaction_read_only_enforced": true, + "manifest_effective_role_is_read_only": true, + "manifest_override_absent_or_exact_canonical_path": true, + "manifest_packet_path_is_exact_canonical_relative_path": true, + "manifest_packet_sha256_matches_canonical_file": true, + "manifest_protocol_binding_matches_packet": true, + "manifest_psql_rc_disabled": true, + "manifest_sql_statically_read_only": true, + "manifest_transaction_read_only_enforced": true, + "packet_check_section_present_and_passing": true, + "packet_does_not_mutate_db": true, + "packet_has_no_authorization_recorded": true, + "packet_messages_exact": true, + "packet_not_sent": true, + "packet_prompt_ids_exact": true, + "packet_protocol_sha256_derivation_valid": true, + "packet_protocol_sha256_present": true, + "packet_protocol_top_level_bindings_match": true, + "packet_ready_for_authorization_request": true, + "packet_requires_authenticated_chrome": true, + "packet_schema_supported": true, + "packet_targets_exact_leo_chat": true, + "packet_tooling_hashes_match_current_sources": true, "postflight_present": false, - "preflight_passed": true + "preflight_baseline_checks_all_pass": true, + "preflight_manifest_bound": true, + "preflight_packet_checks_all_pass": true, + "preflight_packet_file_hash_bound": true, + "preflight_protocol_bound": true, + "preflight_remote_checks_all_pass": true, + "preflight_schema_supported": true, + "preflight_state_token_derivation_valid": true, + "preflight_status_and_phase_pass": true }, "claim_ceiling": { "not_proven": [ @@ -70,7 +106,7 @@ "proven": "The exact packet and live zero-mutation preflight are ready." }, "current_tier": "T0_packet_plus_T3_preflight", - "generated_at_utc": "2026-07-15T01:33:10.948040+00:00", + "generated_at_utc": "2026-07-15T02:34:03.994153+00:00", "mode": "telegram_visible_unseen_chain_capture_verifier", "mutates_db": false, "packet_path": "docs/reports/leo-working-state-20260709/telegram-visible-unseen-chain-authorization-packet-current.json", @@ -78,7 +114,7 @@ "preflight_path": "docs/reports/leo-working-state-20260709/telegram-visible-unseen-chain-preflight-current.json", "receipt_ready": false, "required_tier": "T3_live_readonly", - "schema": "livingip.telegramVisibleUnseenChainReceipt.v1", + "schema": "livingip.telegramVisibleUnseenChainReceipt.v2", "status": "awaiting_action_time_authorization", "telegram_visible_messages_sent": false } diff --git a/docs/reports/leo-working-state-20260709/telegram-visible-unseen-chain-capture-receipt-current.md b/docs/reports/leo-working-state-20260709/telegram-visible-unseen-chain-capture-receipt-current.md index 5d0b2fc..23bbcde 100644 --- a/docs/reports/leo-working-state-20260709/telegram-visible-unseen-chain-capture-receipt-current.md +++ b/docs/reports/leo-working-state-20260709/telegram-visible-unseen-chain-capture-receipt-current.md @@ -1,6 +1,6 @@ # Telegram-Visible Unseen Chain Capture Receipt -Generated UTC: `2026-07-15T01:33:10.948040+00:00` +Generated UTC: `2026-07-15T02:34:03.994153+00:00` Status: `awaiting_action_time_authorization` Receipt ready: `False` Current tier: `T0_packet_plus_T3_preflight` @@ -12,13 +12,46 @@ Mutates DB: `False` - `action_time_authorization_present`: `False` - `capture_present`: `False` -- `packet_ready`: `True` +- `manifest_arbitrary_override_forbidden`: `True` +- `manifest_canonical_path_exists`: `True` +- `manifest_default_transaction_read_only_enforced`: `True` +- `manifest_effective_role_is_read_only`: `True` +- `manifest_override_absent_or_exact_canonical_path`: `True` +- `manifest_packet_path_is_exact_canonical_relative_path`: `True` +- `manifest_packet_sha256_matches_canonical_file`: `True` +- `manifest_protocol_binding_matches_packet`: `True` +- `manifest_psql_rc_disabled`: `True` +- `manifest_sql_statically_read_only`: `True` +- `manifest_transaction_read_only_enforced`: `True` +- `packet_check_section_present_and_passing`: `True` +- `packet_does_not_mutate_db`: `True` +- `packet_has_no_authorization_recorded`: `True` +- `packet_messages_exact`: `True` +- `packet_not_sent`: `True` +- `packet_prompt_ids_exact`: `True` +- `packet_protocol_sha256_derivation_valid`: `True` +- `packet_protocol_sha256_present`: `True` +- `packet_protocol_top_level_bindings_match`: `True` +- `packet_ready_for_authorization_request`: `True` +- `packet_requires_authenticated_chrome`: `True` +- `packet_schema_supported`: `True` +- `packet_targets_exact_leo_chat`: `True` +- `packet_tooling_hashes_match_current_sources`: `True` - `postflight_present`: `False` -- `preflight_passed`: `True` +- `preflight_baseline_checks_all_pass`: `True` +- `preflight_manifest_bound`: `True` +- `preflight_packet_checks_all_pass`: `True` +- `preflight_packet_file_hash_bound`: `True` +- `preflight_protocol_bound`: `True` +- `preflight_remote_checks_all_pass`: `True` +- `preflight_schema_supported`: `True` +- `preflight_state_token_derivation_valid`: `True` +- `preflight_status_and_phase_pass`: `True` ## Awaiting Authorized Capture The packet and preflight are ready. No Telegram message has been sent by this verifier. +A future T3 receipt also requires the exact platform authorization event and Chrome-backend capture receipts from the bound Codex rollout log. ## Claim Ceiling diff --git a/docs/reports/leo-working-state-20260709/telegram-visible-unseen-chain-goal-readback-current.json b/docs/reports/leo-working-state-20260709/telegram-visible-unseen-chain-goal-readback-current.json index 6edb7a0..90ae900 100644 --- a/docs/reports/leo-working-state-20260709/telegram-visible-unseen-chain-goal-readback-current.json +++ b/docs/reports/leo-working-state-20260709/telegram-visible-unseen-chain-goal-readback-current.json @@ -1,6 +1,15 @@ { "fallback_goal_path": "goal.md", - "generated_at_utc": "2026-07-15T01:26:37Z", + "expanded_active_scope": [ + "canonical manifest path and SHA binding with pre-SSH write rejection", + "independent read-only Postgres session and pg_read_all_data effective role", + "supported artifact schemas, passing check sections, and derived state tokens", + "strict timezone-aware authorization/send/reply/capture/postflight chronology", + "evidence-root containment, valid PNG metadata, and distinct per-turn hashes", + "Codex rollout-backed user authorization and Chrome capture provenance", + "full local-forgery regression" + ], + "generated_at_utc": "2026-07-15T02:30:26Z", "platform_goal_after": { "objective": "Complete and verify the Telegram-visible unseen challenge-to-revision canary defined in this goal file while proving zero database mutation.", "status": "active", @@ -11,11 +20,22 @@ "objective": "Complete and verify the Telegram-visible unseen challenge-to-revision canary defined in this goal file while proving zero database mutation.", "status": "active", "thread_id": "019f6350-3350-7040-b223-c5c22673fece", - "time_used_seconds_at_readback": 1116, - "tokens_used_at_readback": 211127 + "time_used_seconds_at_readback": 4474, + "tokens_used_at_readback": 886585 }, "platform_goal_repair_action": "create_goal", "platform_goal_replaced": false, + "platform_goal_scope_update_action": "continued_existing_active_goal_and_expanded_fallback_acceptance_scope", + "platform_goal_scope_update_after": { + "objective": "Complete and verify the Telegram-visible unseen challenge-to-revision canary defined in this goal file while proving zero database mutation.", + "status": "active", + "thread_id": "019f6350-3350-7040-b223-c5c22673fece" + }, + "platform_goal_scope_update_before": { + "objective": "Complete and verify the Telegram-visible unseen challenge-to-revision canary defined in this goal file while proving zero database mutation.", + "status": "active", + "thread_id": "019f6350-3350-7040-b223-c5c22673fece" + }, "schema": "livingip.telegramVisibleUnseenChainGoalReadback.v1", - "why_not_replaced": "No active platform Goal existed, so the canonical Goal was created rather than replaced." + "why_not_replaced": "The active objective already covers T3 Telegram-visible and zero-mutation acceptance. The platform Goal API exposes only complete/blocked status updates while active, so replacing or falsely completing it would be incorrect; expanded integrity acceptance is retained in goal.md and this readback." } diff --git a/docs/reports/leo-working-state-20260709/telegram-visible-unseen-chain-nonsend-proof-current.json b/docs/reports/leo-working-state-20260709/telegram-visible-unseen-chain-nonsend-proof-current.json index e34e552..fbf2e4f 100644 --- a/docs/reports/leo-working-state-20260709/telegram-visible-unseen-chain-nonsend-proof-current.json +++ b/docs/reports/leo-working-state-20260709/telegram-visible-unseen-chain-nonsend-proof-current.json @@ -3,17 +3,22 @@ "collector_or_verifier_processes_remaining": [], "status": "clean" }, - "generated_at_utc": "2026-07-15T01:37:18Z", + "generated_at_utc": "2026-07-15T02:39:17Z", "live_preflight": { "canonical_fingerprint_sha256": "32a1f2c18f4b4c623443cbd4d9520982e9f291ec74ca63855cef51c88ac56f24", "canonical_fingerprint_unchanged_across_two_snapshots": true, - "deployed_git_stamp": "15c30f1fbe30c8f2295ddc33e293a45788a95706", + "capture_challenge_nonce": "0a03b4e74a4533d3bb657d7b07fb48888293d7ba217e776f3c2c120764afe086", + "deployed_git_stamp": "626bac493e2b772db984be7a4a68e9da656f6b02", + "effective_database_role": "pg_read_all_data", "gateway_main_pid": "347406", "gateway_restarts": "0", + "manifest_path": "ops/postgres_parity_manifest.sql", + "manifest_sha256": "8b8cdc25d54fdd8de05eb38c6e4423d2836953eb6012d4545f5c9c71b5f0150a", "mutates_db": false, + "packet_file_sha256": "76fb81d055a726de580d1c0ed75784b4576729e8e67badb6a4574677b2447ed0", "path": "docs/reports/leo-working-state-20260709/telegram-visible-unseen-chain-preflight-current.json", - "packet_file_sha256": "fb0ab4af0396b2064efce1ead44aacc0465ee0e3eacf9b4a7c07abae044d217a", - "protocol_sha256": "c815dad151d640335eecbddd2ca7bb651c43f6c1d4e53642e12c8a35157ac2da", + "preflight_file_sha256": "7705534b35921c7c27fb40acd1277c6ed07ceae114014d074737160f65d4cc6f", + "protocol_sha256": "91cba55a23cac9061ac34a827a040f27eb6a018f720586304dd9b08ed113af77", "readback_attempts": { "deploy": 1, "fingerprint_after": 1, @@ -21,15 +26,18 @@ "service_after": 1, "service_before": 1 }, - "state_token_sha256": "a0af7235b62f88a009184f8f51b6de4b9aec008f6d93ebfa1458f9b77fc208ec", - "tooling_hashes_match_current_sources": true, + "state_token_sha256": "410677869ca2854f38b3e5017de2c682a2625d751fdff6600ac9bc40ce2fbc2e", "status": "pass", "table_count": 39, - "total_rows": 52167 + "tooling_hashes_match_current_sources": true, + "total_rows": 52167, + "transaction_read_only": "on", + "workspace_head_matches_deployed_stamp": true }, "not_tested": [ "Telegram message delivery", "Telegram-visible Leo replies", + "action-time authorization and authenticated-Chrome capture backed by the bound Codex rollout", "post-send selected-object readback", "post-send canonical fingerprint equality" ], @@ -39,6 +47,11 @@ "docs/reports/leo-working-state-20260709/telegram-visible-unseen-chain-capture-receipt-current.json", "docs/reports/leo-working-state-20260709/telegram-visible-unseen-chain-goal-readback-current.json" ], + "receipt_hashes": { + "authorization_packet_sha256": "76fb81d055a726de580d1c0ed75784b4576729e8e67badb6a4574677b2447ed0", + "capture_receipt_sha256": "0573aed8ceaf04c186afa68b5bf1c6687b76059b00725d33f87939f84b2e5401", + "preflight_sha256": "7705534b35921c7c27fb40acd1277c6ed07ceae114014d074737160f65d4cc6f" + }, "schema": "livingip.telegramVisibleUnseenChainNonsendProof.v1", "send_boundary": { "action_time_authorization_present": false, @@ -48,15 +61,23 @@ "tests": [ { "command": "/Users/user/Documents/Codex/2026-07-09/019f34eb-d297-72d0-b7e2-b222d5515ab9-load/work/teleo-infra-main/.venv/bin/pytest -q tests/test_verify_leo_unseen_reasoning_chain.py tests/test_build_telegram_visible_unseen_chain_packet.py tests/test_collect_telegram_visible_unseen_chain_state.py tests/test_verify_telegram_visible_unseen_chain.py", - "result": "24 passed in 0.16s" + "result": "42 passed in 4.19s" }, { "command": "/Users/user/Documents/Codex/2026-07-09/019f34eb-d297-72d0-b7e2-b222d5515ab9-load/work/teleo-infra-main/.venv/bin/pytest -q", - "result": "1293 passed in 102.03s" + "result": "1319 passed in 81.44s" }, { - "command": "/Users/user/Documents/Codex/2026-07-09/019f34eb-d297-72d0-b7e2-b222d5515ab9-load/work/teleo-infra-main/.venv/bin/ruff check ", + "command": "/Users/user/Documents/Codex/2026-07-09/019f34eb-d297-72d0-b7e2-b222d5515ab9-load/work/teleo-infra-main/.venv/bin/ruff check scripts/build_telegram_visible_unseen_chain_packet.py scripts/collect_telegram_visible_unseen_chain_state.py scripts/verify_telegram_visible_unseen_chain.py tests/test_build_telegram_visible_unseen_chain_packet.py tests/test_collect_telegram_visible_unseen_chain_state.py tests/test_verify_telegram_visible_unseen_chain.py", "result": "All checks passed" + }, + { + "command": "/Users/user/Documents/Codex/2026-07-09/019f34eb-d297-72d0-b7e2-b222d5515ab9-load/work/teleo-infra-main/.venv/bin/ruff format --check scripts/build_telegram_visible_unseen_chain_packet.py scripts/collect_telegram_visible_unseen_chain_state.py scripts/verify_telegram_visible_unseen_chain.py tests/test_build_telegram_visible_unseen_chain_packet.py tests/test_collect_telegram_visible_unseen_chain_state.py tests/test_verify_telegram_visible_unseen_chain.py", + "result": "6 files already formatted" + }, + { + "command": "git diff --check", + "result": "pass" } ] } diff --git a/docs/reports/leo-working-state-20260709/telegram-visible-unseen-chain-preflight-current.json b/docs/reports/leo-working-state-20260709/telegram-visible-unseen-chain-preflight-current.json index 3af9b9e..f573d7f 100644 --- a/docs/reports/leo-working-state-20260709/telegram-visible-unseen-chain-preflight-current.json +++ b/docs/reports/leo-working-state-20260709/telegram-visible-unseen-chain-preflight-current.json @@ -1,6 +1,7 @@ { "baseline_checks": {}, "baseline_path": "", + "baseline_state_token_sha256": "", "blocker_readback": { "attempted_routes": [ "local exact packet validation", @@ -12,6 +13,7 @@ "exact_gate": "", "next_non_user_action": "Run the authenticated-Chrome three-turn flow only after exact authorization, then collect postflight." }, + "capture_challenge_nonce": "0a03b4e74a4533d3bb657d7b07fb48888293d7ba217e776f3c2c120764afe086", "claim_ceiling": { "current_tier": "T3_live_readonly", "not_proven": [ @@ -21,33 +23,63 @@ ], "proven": "Two canonical read-only snapshots and the gateway process were unchanged during this probe." }, - "generated_at_utc": "2026-07-15T01:33:10.551000+00:00", + "generated_at_utc": "2026-07-15T02:33:56.887524+00:00", + "manifest_binding": { + "execution_contract": { + "arbitrary_manifest_override_allowed": false, + "authenticated_role": "postgres", + "database": "teleo", + "default_transaction_read_only": "on", + "effective_role": "pg_read_all_data", + "psql_rc_disabled": true, + "transaction_read_only": "on" + }, + "path": "ops/postgres_parity_manifest.sql", + "sha256": "8b8cdc25d54fdd8de05eb38c6e4423d2836953eb6012d4545f5c9c71b5f0150a" + }, "mode": "telegram_visible_unseen_chain_zero_mutation_state_readback", "mutates_db": false, "packet_checks": { + "manifest_arbitrary_override_forbidden": true, + "manifest_canonical_path_exists": true, + "manifest_default_transaction_read_only_enforced": true, + "manifest_effective_role_is_read_only": true, + "manifest_loaded_bytes_match_bound_sha256": true, + "manifest_loaded_bytes_revalidated_read_only": true, + "manifest_override_absent_or_exact_canonical_path": true, + "manifest_packet_path_is_exact_canonical_relative_path": true, + "manifest_packet_sha256_matches_canonical_file": true, + "manifest_protocol_binding_matches_packet": true, + "manifest_psql_rc_disabled": true, + "manifest_sql_statically_read_only": true, + "manifest_transaction_read_only_enforced": true, + "packet_check_section_present_and_passing": true, "packet_does_not_mutate_db": true, "packet_has_no_authorization_recorded": true, "packet_messages_exact": true, "packet_not_sent": true, "packet_prompt_ids_exact": true, + "packet_protocol_sha256_derivation_valid": true, "packet_protocol_sha256_present": true, + "packet_protocol_top_level_bindings_match": true, "packet_ready_for_authorization_request": true, "packet_requires_authenticated_chrome": true, "packet_schema_supported": true, "packet_targets_exact_leo_chat": true, "packet_tooling_hashes_match_current_sources": true }, - "packet_file_sha256": "fb0ab4af0396b2064efce1ead44aacc0465ee0e3eacf9b4a7c07abae044d217a", + "packet_file_sha256": "76fb81d055a726de580d1c0ed75784b4576729e8e67badb6a4574677b2447ed0", "packet_path": "docs/reports/leo-working-state-20260709/telegram-visible-unseen-chain-authorization-packet-current.json", "phase": "preflight", "production_apply_executed": false, - "protocol_sha256": "c815dad151d640335eecbddd2ca7bb651c43f6c1d4e53642e12c8a35157ac2da", + "protocol_sha256": "91cba55a23cac9061ac34a827a040f27eb6a018f720586304dd9b08ed113af77", "ready_for_action_time_authorization": true, "ready_for_visible_capture_verification": false, "remote": { - "deploy_head": "15c30f1fbe30c8f2295ddc33e293a45788a95706", + "deploy_head": "626bac493e2b772db984be7a4a68e9da656f6b02", "deploy_stamp_ancestor": true, "fingerprint_after": { + "current_user": "pg_read_all_data", "fingerprint_sha256": "32a1f2c18f4b4c623443cbd4d9520982e9f291ec74ca63855cef51c88ac56f24", "schema": "livingip.teleoCanonicalDatabaseFingerprint.v1", "status": "ok", @@ -58,6 +90,7 @@ "transaction_read_only": "on" }, "fingerprint_before": { + "current_user": "pg_read_all_data", "fingerprint_sha256": "32a1f2c18f4b4c623443cbd4d9520982e9f291ec74ca63855cef51c88ac56f24", "schema": "livingip.teleoCanonicalDatabaseFingerprint.v1", "status": "ok", @@ -67,7 +100,7 @@ "total_rows": 52167, "transaction_read_only": "on" }, - "last_deploy_sha": "15c30f1fbe30c8f2295ddc33e293a45788a95706", + "last_deploy_sha": "626bac493e2b772db984be7a4a68e9da656f6b02", "readback_attempts": { "deploy": 1, "fingerprint_after": 1, @@ -97,6 +130,7 @@ "deployed_stamp_is_ancestor_of_workspace_head": true, "deployed_stamp_is_sha": true, "fingerprints_are_read_only": true, + "fingerprints_use_independent_read_only_role": true, "first_fingerprint_complete": true, "second_fingerprint_complete": true, "service_active_before_and_after": true, @@ -107,8 +141,8 @@ }, "remote_returncode": 0, "remote_stderr": "", - "schema": "livingip.telegramVisibleUnseenChainState.v1", - "state_token_sha256": "a0af7235b62f88a009184f8f51b6de4b9aec008f6d93ebfa1458f9b77fc208ec", + "schema": "livingip.telegramVisibleUnseenChainState.v2", + "state_token_sha256": "410677869ca2854f38b3e5017de2c682a2625d751fdff6600ac9bc40ce2fbc2e", "status": "pass", "subject_ref": "", "telegram_visible_messages_sent_by_collector": false diff --git a/docs/reports/leo-working-state-20260709/telegram-visible-unseen-chain-preflight-current.md b/docs/reports/leo-working-state-20260709/telegram-visible-unseen-chain-preflight-current.md index c4e17c6..acea11a 100644 --- a/docs/reports/leo-working-state-20260709/telegram-visible-unseen-chain-preflight-current.md +++ b/docs/reports/leo-working-state-20260709/telegram-visible-unseen-chain-preflight-current.md @@ -1,21 +1,37 @@ # Telegram-Visible Unseen Chain Preflight -Generated UTC: `2026-07-15T01:33:10.551000+00:00` +Generated UTC: `2026-07-15T02:33:56.887524+00:00` Status: `pass` -Protocol SHA256: `c815dad151d640335eecbddd2ca7bb651c43f6c1d4e53642e12c8a35157ac2da` -Packet file SHA256: `fb0ab4af0396b2064efce1ead44aacc0465ee0e3eacf9b4a7c07abae044d217a` -State token SHA256: `a0af7235b62f88a009184f8f51b6de4b9aec008f6d93ebfa1458f9b77fc208ec` +Protocol SHA256: `91cba55a23cac9061ac34a827a040f27eb6a018f720586304dd9b08ed113af77` +Packet file SHA256: `76fb81d055a726de580d1c0ed75784b4576729e8e67badb6a4574677b2447ed0` +State token SHA256: `410677869ca2854f38b3e5017de2c682a2625d751fdff6600ac9bc40ce2fbc2e` Messages sent by collector: `False` Mutates DB: `False` ## Checks +- `manifest_arbitrary_override_forbidden`: `True` +- `manifest_canonical_path_exists`: `True` +- `manifest_default_transaction_read_only_enforced`: `True` +- `manifest_effective_role_is_read_only`: `True` +- `manifest_loaded_bytes_match_bound_sha256`: `True` +- `manifest_loaded_bytes_revalidated_read_only`: `True` +- `manifest_override_absent_or_exact_canonical_path`: `True` +- `manifest_packet_path_is_exact_canonical_relative_path`: `True` +- `manifest_packet_sha256_matches_canonical_file`: `True` +- `manifest_protocol_binding_matches_packet`: `True` +- `manifest_psql_rc_disabled`: `True` +- `manifest_sql_statically_read_only`: `True` +- `manifest_transaction_read_only_enforced`: `True` +- `packet_check_section_present_and_passing`: `True` - `packet_does_not_mutate_db`: `True` - `packet_has_no_authorization_recorded`: `True` - `packet_messages_exact`: `True` - `packet_not_sent`: `True` - `packet_prompt_ids_exact`: `True` +- `packet_protocol_sha256_derivation_valid`: `True` - `packet_protocol_sha256_present`: `True` +- `packet_protocol_top_level_bindings_match`: `True` - `packet_ready_for_authorization_request`: `True` - `packet_requires_authenticated_chrome`: `True` - `packet_schema_supported`: `True` @@ -25,6 +41,7 @@ Mutates DB: `False` - `deployed_stamp_is_ancestor_of_workspace_head`: `True` - `deployed_stamp_is_sha`: `True` - `fingerprints_are_read_only`: `True` +- `fingerprints_use_independent_read_only_role`: `True` - `first_fingerprint_complete`: `True` - `second_fingerprint_complete`: `True` - `service_active_before_and_after`: `True` @@ -35,10 +52,14 @@ Mutates DB: `False` ## Live Readback -- Deploy head: `15c30f1fbe30c8f2295ddc33e293a45788a95706` -- Deploy stamp: `15c30f1fbe30c8f2295ddc33e293a45788a95706` +- Deploy head: `626bac493e2b772db984be7a4a68e9da656f6b02` +- Deploy stamp: `626bac493e2b772db984be7a4a68e9da656f6b02` - Gateway MainPID: `347406` - Gateway NRestarts: `0` +- Manifest: `ops/postgres_parity_manifest.sql` +- Manifest SHA256: `8b8cdc25d54fdd8de05eb38c6e4423d2836953eb6012d4545f5c9c71b5f0150a` +- Effective DB role: `pg_read_all_data` +- Transaction read only: `on` - Canonical fingerprint: `32a1f2c18f4b4c623443cbd4d9520982e9f291ec74ca63855cef51c88ac56f24` - Canonical tables: `39` - Canonical rows: `52167` diff --git a/scripts/build_telegram_visible_unseen_chain_packet.py b/scripts/build_telegram_visible_unseen_chain_packet.py index 8a22800..10d6bdd 100644 --- a/scripts/build_telegram_visible_unseen_chain_packet.py +++ b/scripts/build_telegram_visible_unseen_chain_packet.py @@ -16,7 +16,8 @@ try: except ImportError: # pragma: no cover - imported as scripts.* in tests from scripts import verify_leo_unseen_reasoning_chain as unseen -SCHEMA = "livingip.telegramVisibleUnseenChainPacket.v1" +SCHEMA = "livingip.telegramVisibleUnseenChainPacket.v2" +REPO_ROOT = Path(__file__).resolve().parents[1] REPORT_DIR = Path("docs/reports/leo-working-state-20260709") DEFAULT_HANDLER_RECEIPT = REPORT_DIR / "leo-unseen-reasoning-chain-canary-current.json" DEFAULT_OUT = REPORT_DIR / "telegram-visible-unseen-chain-authorization-packet-current.json" @@ -27,6 +28,9 @@ DEFAULT_POSTFLIGHT = REPORT_DIR / "telegram-visible-unseen-chain-postflight-curr DEFAULT_CHAT_ID = "-5146042086" DEFAULT_CHAT_LABEL = "Leo" DEFAULT_PROOF_DIR = "outputs/telegram-visible-unseen-chain-20260715" +DEFAULT_MANIFEST_SQL = Path("ops/postgres_parity_manifest.sql") +READ_ONLY_DB_ROLE = "pg_read_all_data" +DEFAULT_CODEX_THREAD_ID = "019f6350-3350-7040-b223-c5c22673fece" TOOLING_PATHS = { "packet_builder": Path("scripts/build_telegram_visible_unseen_chain_packet.py"), "state_collector": Path("scripts/collect_telegram_visible_unseen_chain_state.py"), @@ -79,10 +83,26 @@ def exact_messages() -> list[dict[str, Any]]: return messages -def tooling_binding(repo_root: Path = Path(".")) -> dict[str, dict[str, Any]]: +def tooling_binding(repo_root: Path = REPO_ROOT) -> dict[str, dict[str, Any]]: return {name: {"path": str(path), "sha256": _sha256_file(repo_root / path)} for name, path in TOOLING_PATHS.items()} +def manifest_binding(repo_root: Path = REPO_ROOT) -> dict[str, Any]: + return { + "path": str(DEFAULT_MANIFEST_SQL), + "sha256": _sha256_file(repo_root / DEFAULT_MANIFEST_SQL), + "execution_contract": { + "database": "teleo", + "authenticated_role": "postgres", + "effective_role": READ_ONLY_DB_ROLE, + "default_transaction_read_only": "on", + "transaction_read_only": "on", + "psql_rc_disabled": True, + "arbitrary_manifest_override_allowed": False, + }, + } + + def _handler_checks(receipt: dict[str, Any]) -> dict[str, bool]: safety = receipt.get("safety_gate") if isinstance(receipt.get("safety_gate"), dict) else {} safety_checks = safety.get("checks") if isinstance(safety.get("checks"), dict) else {} @@ -113,7 +133,9 @@ def _authorization_text(*, chat_label: str, chat_id: str, messages: list[dict[st "I authorize Codex to use the already-authenticated Chrome Telegram UI to send exactly these three " f"messages, in order and with no additional messages, to the Telegram group {chat_label} (chat ID " f"{chat_id}), waiting for Leo's visible reply after each turn: {quoted} Capture the visible replies, " - "message IDs, timestamps, screenshot and accessibility evidence; perform only read-only DB/service " + "message IDs, timestamps, screenshot and accessibility evidence, plus an independently retained Chrome " + "control provenance receipt bound to the Codex rollout's user-authorization and Chrome tool events; " + "perform only read-only DB/service " "readbacks; do not use the Bot API; do not stage, approve, apply, or otherwise mutate knowledge." ) @@ -124,6 +146,7 @@ def build_packet( chat_id: str = DEFAULT_CHAT_ID, chat_label: str = DEFAULT_CHAT_LABEL, proof_dir: str = DEFAULT_PROOF_DIR, + codex_thread_id: str = DEFAULT_CODEX_THREAD_ID, git_sha: str | None = None, ) -> dict[str, Any]: handler_receipt = _load_json(handler_receipt_path) @@ -148,15 +171,35 @@ def build_packet( "fingerprint_sha256": (handler_receipt.get("database") or {}).get("fingerprint_sha256"), } tooling = tooling_binding() + manifest = manifest_binding() + browser_provenance_contract = { + "schema": "livingip.authenticatedChromeTelegramCaptureProvenance.v1", + "capture_channel": "codex_chrome_extension", + "requires_preflight_challenge_nonce": True, + "requires_codex_rollout_log_outside_evidence_root": True, + "requires_chrome_backend_tool_receipts": True, + "requires_provenance_sha256_in_final_chrome_tool_receipt": True, + "requires_codex_user_message_authorization_receipt": True, + "requires_browser_session_tab_and_capture_identifiers": True, + "requires_telegram_web_origin_and_chat_identity": True, + "requires_hashes_for_every_screenshot_and_accessibility_artifact": True, + } protocol = { "target": target, "exact_messages": messages, "handler_binding": handler_binding, "tooling_binding": tooling, + "manifest_binding": manifest, + "browser_provenance_contract": browser_provenance_contract, + "operator_context": { + "codex_thread_id": codex_thread_id, + "authorization_source": "codex_platform_user_message", + }, "state_contract": { "preflight": "two identical repeatable-read read-only canonical fingerprints", "postflight": "same canonical fingerprint plus independent selected-object readback", "service": "same active gateway process before and after", + "ordering": "preflight < authorization < send1 < reply1 < send2 < reply2 < send3 < reply3 < final/postflight", }, } protocol_sha256 = _canonical_sha256(protocol) @@ -168,6 +211,16 @@ def build_packet( "first_prompt_supplies_no_row_id": unseen.UUID_RE.search(messages[0]["message"]) is None, "authenticated_chrome_is_only_send_transport": target["allowed_transport"] == "authenticated_chrome_telegram_ui", + "canonical_manifest_path_and_sha_bound": manifest == manifest_binding(), + "database_session_and_role_fail_closed_read_only": manifest["execution_contract"]["effective_role"] + == READ_ONLY_DB_ROLE + and manifest["execution_contract"]["default_transaction_read_only"] == "on" + and manifest["execution_contract"]["transaction_read_only"] == "on" + and manifest["execution_contract"]["arbitrary_manifest_override_allowed"] is False, + "independent_browser_provenance_required": browser_provenance_contract[ + "requires_codex_rollout_log_outside_evidence_root" + ] + is True, "packet_does_not_send": True, "packet_does_not_mutate_database": True, } @@ -182,6 +235,7 @@ def build_packet( "turn_accessibility": [f"{proof_dir}/turn-{index}-accessibility.txt" for index in range(1, 4)], "final_screenshot": f"{proof_dir}/final.png", "final_accessibility": f"{proof_dir}/final-accessibility.txt", + "browser_provenance": f"{proof_dir}/browser-provenance.json", } return { "schema": SCHEMA, @@ -189,6 +243,7 @@ def build_packet( "mode": "telegram_visible_unseen_chain_exact_packet_not_sent", "packet_generation_git_sha": git_sha if git_sha is not None else current_git_sha(), "protocol_sha256": protocol_sha256, + "protocol": protocol, "ready_to_request_action_time_authorization": ready, "authorization_gate_status": "ready_to_request_exact_authorization" if ready else "not_ready", "telegram_visible_messages_sent": False, @@ -199,6 +254,9 @@ def build_packet( "exact_messages": messages, "handler_receipt_binding": handler_binding, "tooling_binding": tooling, + "manifest_binding": manifest, + "browser_provenance_contract": browser_provenance_contract, + "operator_context": protocol["operator_context"], "checks": checks, "expected_proof_paths_after_authorized_run": proof_paths, "explicit_operator_authorization_text": authorization_text, @@ -210,7 +268,8 @@ def build_packet( "Re-run the zero-mutation preflight and confirm its packet file hash is current.", "Use authenticated Chrome only and verify the Leo chat ID before typing anything.", "Send one exact message, wait for Leo's visible reply, then continue to the next exact message.", - "Capture message IDs, timestamps, screenshot, and accessibility text without copying handler output.", + "Capture message IDs, timestamps, screenshot, accessibility text, and the Chrome-control provenance receipt without copying handler output.", + "Retain the Codex rollout path whose Chrome tool receipt contains the provenance SHA256.", "Extract the selected DB object reference and run the read-only postflight with that reference.", "Run the Telegram-visible verifier and accept T3 only if every visible and state check passes.", ], @@ -262,7 +321,28 @@ def write_markdown(path: Path, data: dict[str, Any]) -> None: "", ] ) - lines.extend(["## Checks", ""]) + manifest = data["manifest_binding"] + execution = manifest["execution_contract"] + lines.extend( + [ + "## Read-Only State Contract", + "", + f"- Manifest: `{manifest['path']}`", + f"- Manifest SHA256: `{manifest['sha256']}`", + f"- Effective DB role: `{execution['effective_role']}`", + f"- Transaction read only: `{execution['transaction_read_only']}`", + f"- Arbitrary manifest override allowed: `{execution['arbitrary_manifest_override_allowed']}`", + "", + "## Independent Capture Contract", + "", + f"- Codex thread: `{data['operator_context']['codex_thread_id']}`", + "- Authorization must be an exact platform user-message event in that thread's rollout.", + "- Each turn and final artifact must be bound by Chrome-backend tool receipts in that rollout.", + "", + "## Checks", + "", + ] + ) lines.extend(f"- `{key}`: `{value}`" for key, value in sorted(data["checks"].items())) lines.extend( [ diff --git a/scripts/collect_telegram_visible_unseen_chain_state.py b/scripts/collect_telegram_visible_unseen_chain_state.py index 2558539..0add98e 100644 --- a/scripts/collect_telegram_visible_unseen_chain_state.py +++ b/scripts/collect_telegram_visible_unseen_chain_state.py @@ -7,6 +7,7 @@ import argparse import hashlib import json import re +import secrets import shlex import subprocess from collections.abc import Callable @@ -22,7 +23,8 @@ except ImportError: # pragma: no cover - imported as scripts.* in tests from scripts import build_telegram_visible_unseen_chain_packet as packet_builder from scripts import verify_leo_unseen_reasoning_chain as unseen -SCHEMA = "livingip.telegramVisibleUnseenChainState.v1" +SCHEMA = "livingip.telegramVisibleUnseenChainState.v2" +REPO_ROOT = Path(__file__).resolve().parents[1] REPORT_DIR = Path("docs/reports/leo-working-state-20260709") DEFAULT_PACKET = packet_builder.DEFAULT_OUT DEFAULT_PREFLIGHT_OUT = REPORT_DIR / "telegram-visible-unseen-chain-preflight-current.json" @@ -31,13 +33,24 @@ DEFAULT_POSTFLIGHT_OUT = REPORT_DIR / "telegram-visible-unseen-chain-postflight- DEFAULT_POSTFLIGHT_MARKDOWN_OUT = REPORT_DIR / "telegram-visible-unseen-chain-postflight-current.md" DEFAULT_SSH_TARGET = "root@77.42.65.182" DEFAULT_SSH_KEY = Path.home() / ".ssh/livingip_hetzner_20260604_ed25519" -DEFAULT_MANIFEST_SQL = Path("ops/postgres_parity_manifest.sql") +DEFAULT_MANIFEST_SQL = packet_builder.DEFAULT_MANIFEST_SQL REMOTE_REPO = "/opt/teleo-eval/workspaces/deploy-infra" SUBJECT_REF_RE = re.compile( r"^(?:[0-9a-f]{8}|[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12})$", re.IGNORECASE, ) SHA40_RE = re.compile(r"^[0-9a-f]{40}$") +SHA64_RE = re.compile(r"^[0-9a-f]{64}$") +FORBIDDEN_MANIFEST_SQL_RE = re.compile( + r"\b(?:insert|update|delete|merge|create|alter|drop|truncate|grant|revoke|copy|call|do|vacuum|" + r"refresh|reindex|cluster|commit|prepare|execute)\b|" + r"\\(?:!|i|ir|include|include_relative|copy)\b|" + r"\bset\s+(?:session\s+authorization|role)\b|" + r"\breset\s+(?:session\s+authorization|role)\b|" + r"\b(?:default_)?transaction_read_only\s*=\s*(?:off|false|0)\b|" + r"\btransaction\s+read\s+write\b", + re.IGNORECASE, +) @dataclass(frozen=True) @@ -78,6 +91,47 @@ def _sha256_file(path: Path) -> str: return hashlib.sha256(path.read_bytes()).hexdigest() +def canonical_manifest_path() -> Path: + return (REPO_ROOT / DEFAULT_MANIFEST_SQL).resolve() + + +def _manifest_sql_is_statically_read_only(sql: str) -> bool: + normalized = re.sub(r"\s+", " ", sql).strip().casefold() + return ( + normalized.startswith(r"\set on_error_stop on") + and "begin transaction isolation level repeatable read read only;" in normalized + and normalized.endswith("rollback;") + and FORBIDDEN_MANIFEST_SQL_RE.search(sql) is None + ) + + +def manifest_checks(packet: dict[str, Any], requested_path: Path | None = None) -> dict[str, bool]: + canonical_path = canonical_manifest_path() + binding = packet.get("manifest_binding") if isinstance(packet.get("manifest_binding"), dict) else {} + protocol = packet.get("protocol") if isinstance(packet.get("protocol"), dict) else {} + execution = binding.get("execution_contract") if isinstance(binding.get("execution_contract"), dict) else {} + try: + sql = canonical_path.read_text(encoding="utf-8") + actual_sha256 = _sha256_file(canonical_path) + except OSError: + sql = "" + actual_sha256 = "" + override_path = requested_path.resolve() if requested_path is not None else canonical_path + return { + "manifest_canonical_path_exists": canonical_path.is_file(), + "manifest_override_absent_or_exact_canonical_path": override_path == canonical_path, + "manifest_packet_path_is_exact_canonical_relative_path": binding.get("path") == str(DEFAULT_MANIFEST_SQL), + "manifest_packet_sha256_matches_canonical_file": bool(actual_sha256) and binding.get("sha256") == actual_sha256, + "manifest_protocol_binding_matches_packet": protocol.get("manifest_binding") == binding, + "manifest_sql_statically_read_only": bool(sql) and _manifest_sql_is_statically_read_only(sql), + "manifest_effective_role_is_read_only": execution.get("effective_role") == packet_builder.READ_ONLY_DB_ROLE, + "manifest_default_transaction_read_only_enforced": execution.get("default_transaction_read_only") == "on", + "manifest_transaction_read_only_enforced": execution.get("transaction_read_only") == "on", + "manifest_psql_rc_disabled": execution.get("psql_rc_disabled") is True, + "manifest_arbitrary_override_forbidden": execution.get("arbitrary_manifest_override_allowed") is False, + } + + def parse_key_value_lines(text: str) -> dict[str, str]: values: dict[str, str] = {} for line in text.splitlines(): @@ -152,15 +206,20 @@ def parse_manifest_output(raw: str) -> dict[str, Any]: "table_rows_sha256": _canonical_sha256(tables), "structure_sha256": _canonical_sha256(stable["singleton_sha256"]), "transaction_read_only": identity.get("transaction_read_only"), + "current_user": identity.get("current_user"), } -def packet_checks(packet: dict[str, Any]) -> dict[str, bool]: +def packet_checks(packet: dict[str, Any], *, requested_manifest_path: Path | None = None) -> dict[str, bool]: target = packet.get("target") if isinstance(packet.get("target"), dict) else {} + protocol = packet.get("protocol") if isinstance(packet.get("protocol"), dict) else {} + packet_check_section = packet.get("checks") if isinstance(packet.get("checks"), dict) else {} exact = packet_builder.exact_messages() expected_tooling = packet_builder.tooling_binding() - return { + checks = { "packet_schema_supported": packet.get("schema") == packet_builder.SCHEMA, + "packet_check_section_present_and_passing": bool(packet_check_section) + and all(value is True for value in packet_check_section.values()), "packet_ready_for_authorization_request": packet.get("ready_to_request_action_time_authorization") is True, "packet_not_sent": packet.get("telegram_visible_messages_sent") is False, "packet_has_no_authorization_recorded": packet.get("telegram_visible_message_authorization_present") is False, @@ -171,10 +230,19 @@ def packet_checks(packet: dict[str, Any]) -> dict[str, bool]: "packet_prompt_ids_exact": target.get("expected_prompt_ids") == [item["id"] for item in unseen.PROMPTS], "packet_messages_exact": [item.get("message") for item in packet.get("exact_messages", [])] == [item["message"] for item in exact], - "packet_protocol_sha256_present": isinstance(packet.get("protocol_sha256"), str) - and len(packet["protocol_sha256"]) == 64, + "packet_protocol_sha256_present": bool(SHA64_RE.fullmatch(str(packet.get("protocol_sha256") or ""))), + "packet_protocol_sha256_derivation_valid": bool(protocol) + and packet.get("protocol_sha256") == _canonical_sha256(protocol), + "packet_protocol_top_level_bindings_match": protocol.get("target") == packet.get("target") + and protocol.get("exact_messages") == packet.get("exact_messages") + and protocol.get("handler_binding") == packet.get("handler_receipt_binding") + and protocol.get("tooling_binding") == packet.get("tooling_binding") + and protocol.get("browser_provenance_contract") == packet.get("browser_provenance_contract") + and protocol.get("operator_context") == packet.get("operator_context"), "packet_tooling_hashes_match_current_sources": packet.get("tooling_binding") == expected_tooling, } + checks.update(manifest_checks(packet, requested_path=requested_manifest_path)) + return checks def ssh_command(args: argparse.Namespace, remote_command: str) -> list[str]: @@ -213,7 +281,11 @@ def service_readback_command() -> str: def fingerprint_readback_command() -> str: - return "docker exec -i teleo-pg psql -U postgres -d teleo -At -q -v ON_ERROR_STOP=1" + pgoptions = shlex.quote( + "PGOPTIONS=-c default_transaction_read_only=on -c transaction_read_only=on " + f"-c role={packet_builder.READ_ONLY_DB_ROLE}" + ) + return f"docker exec -e {pgoptions} -i teleo-pg psql -X -U postgres -d teleo -At -q -v ON_ERROR_STOP=1" def subject_readback_sql(subject_ref: str) -> str: @@ -262,8 +334,12 @@ def _parse_single_json_line(raw: str) -> dict[str, Any] | None: return None -def collect_remote(args: argparse.Namespace, runner: Runner) -> tuple[dict[str, Any], int, str]: - manifest_sql = args.manifest_sql.read_text(encoding="utf-8") +def collect_remote( + args: argparse.Namespace, + runner: Runner, + *, + manifest_sql: str, +) -> tuple[dict[str, Any], int, str]: calls: list[tuple[str, list[str], str, int]] = [ ("deploy", ssh_command(args, deploy_readback_command()), "", args.timeout), ("service_before", ssh_command(args, service_readback_command()), "", args.timeout), @@ -370,6 +446,8 @@ def _remote_checks( "second_fingerprint_complete": after.get("status") == "ok" and int(after.get("table_count") or 0) > 0, "fingerprints_are_read_only": before.get("transaction_read_only") == "on" and after.get("transaction_read_only") == "on", + "fingerprints_use_independent_read_only_role": before.get("current_user") == packet_builder.READ_ONLY_DB_ROLE + and after.get("current_user") == packet_builder.READ_ONLY_DB_ROLE, "canonical_fingerprint_unchanged_during_probe": bool(before.get("fingerprint_sha256")) and before.get("fingerprint_sha256") == after.get("fingerprint_sha256"), } @@ -385,10 +463,80 @@ def _remote_checks( return checks +def derive_state_token(artifact: dict[str, Any]) -> str: + return _canonical_sha256( + { + "schema": artifact.get("schema"), + "generated_at_utc": artifact.get("generated_at_utc"), + "phase": artifact.get("phase"), + "packet_file_sha256": artifact.get("packet_file_sha256"), + "protocol_sha256": artifact.get("protocol_sha256"), + "manifest_binding": artifact.get("manifest_binding"), + "capture_challenge_nonce": artifact.get("capture_challenge_nonce"), + "baseline_state_token_sha256": artifact.get("baseline_state_token_sha256"), + "subject_ref": artifact.get("subject_ref"), + "packet_checks": artifact.get("packet_checks"), + "remote_checks": artifact.get("remote_checks"), + "baseline_checks": artifact.get("baseline_checks"), + "remote": { + "deploy_head": (artifact.get("remote") or {}).get("deploy_head"), + "last_deploy_sha": (artifact.get("remote") or {}).get("last_deploy_sha"), + "service_after": _service_identity((artifact.get("remote") or {}).get("service_after") or {}), + "fingerprint_after": (artifact.get("remote") or {}).get("fingerprint_after"), + "subject_readback": (artifact.get("remote") or {}).get("subject_readback"), + }, + } + ) + + +def state_token_is_valid(artifact: dict[str, Any]) -> bool: + token = artifact.get("state_token_sha256") + return bool(SHA64_RE.fullmatch(str(token or ""))) and token == derive_state_token(artifact) + + +def _empty_remote() -> dict[str, Any]: + return { + "deploy_head": "", + "last_deploy_sha": "", + "deploy_stamp_ancestor": False, + "workspace_head_matches_deployed_stamp": False, + "service_before": {}, + "service_after": {}, + "fingerprint_before": {}, + "fingerprint_after": {}, + "subject_readback": None, + "readback_attempts": {}, + } + + def collect_state(args: argparse.Namespace, *, runner: Runner = subprocess_runner) -> dict[str, Any]: packet = _load_json(args.packet) - local_packet_checks = packet_checks(packet) - remote, remote_returncode, remote_stderr = collect_remote(args, runner) + requested_manifest_path = getattr(args, "manifest_sql", None) + local_packet_checks = packet_checks(packet, requested_manifest_path=requested_manifest_path) + manifest_sql = "" + if all(local_packet_checks.values()): + try: + manifest_sql = canonical_manifest_path().read_text(encoding="utf-8") + except OSError: + manifest_sql = "" + loaded_sha256 = hashlib.sha256(manifest_sql.encode("utf-8")).hexdigest() + local_packet_checks.update( + { + "manifest_loaded_bytes_match_bound_sha256": loaded_sha256 + == (packet.get("manifest_binding") or {}).get("sha256"), + "manifest_loaded_bytes_revalidated_read_only": _manifest_sql_is_statically_read_only(manifest_sql), + } + ) + if all(local_packet_checks.values()): + remote, remote_returncode, remote_stderr = collect_remote( + args, + runner, + manifest_sql=manifest_sql, + ) + else: + remote = _empty_remote() + remote_returncode = 1 + remote_stderr = "local fail-closed validation rejected execution before SSH" remote_checks = _remote_checks( remote, returncode=remote_returncode, @@ -398,17 +546,30 @@ def collect_state(args: argparse.Namespace, *, runner: Runner = subprocess_runne baseline = _load_json(args.baseline) if args.baseline else None baseline_checks: dict[str, bool] = {} if args.phase == "postflight": + baseline_packet_checks = baseline.get("packet_checks") if isinstance(baseline, dict) else {} + baseline_remote_checks = baseline.get("remote_checks") if isinstance(baseline, dict) else {} + baseline_nonce = str((baseline or {}).get("capture_challenge_nonce") or "") baseline_checks = { "baseline_supplied": baseline is not None, + "baseline_schema_supported": bool(baseline and baseline.get("schema") == SCHEMA), "baseline_is_passing_preflight": bool( baseline and baseline.get("phase") == "preflight" and baseline.get("status") == "pass" ), + "baseline_check_sections_all_pass": bool(baseline_packet_checks) + and all(value is True for value in baseline_packet_checks.values()) + and bool(baseline_remote_checks) + and all(value is True for value in baseline_remote_checks.values()), + "baseline_state_token_derivation_valid": bool(baseline and state_token_is_valid(baseline)), + "baseline_capture_challenge_nonce_valid": bool(SHA64_RE.fullmatch(baseline_nonce)), "baseline_protocol_matches_packet": bool( baseline and baseline.get("protocol_sha256") == packet.get("protocol_sha256") ), "baseline_packet_file_matches": bool( baseline and baseline.get("packet_file_sha256") == _sha256_file(args.packet) ), + "baseline_manifest_binding_matches_packet": bool( + baseline and baseline.get("manifest_binding") == packet.get("manifest_binding") + ), "canonical_fingerprint_matches_preflight": bool( baseline and (baseline.get("remote") or {}).get("fingerprint_after", {}).get("fingerprint_sha256") @@ -426,16 +587,14 @@ def collect_state(args: argparse.Namespace, *, runner: Runner = subprocess_runne else "fail" ) packet_file_sha256 = _sha256_file(args.packet) - state_token = _canonical_sha256( - { - "phase": args.phase, - "packet_file_sha256": packet_file_sha256, - "protocol_sha256": packet.get("protocol_sha256"), - "deploy_head": remote.get("deploy_head"), - "service": _service_identity(remote.get("service_after") or {}), - "fingerprint": remote.get("fingerprint_after"), - "subject_readback": remote.get("subject_readback"), - } + generated_at_utc = datetime.now(timezone.utc).isoformat() + capture_challenge_nonce = ( + secrets.token_hex(32) + if args.phase == "preflight" + else str((baseline or {}).get("capture_challenge_nonce") or "") + ) + baseline_state_token_sha256 = ( + str((baseline or {}).get("state_token_sha256") or "") if args.phase == "postflight" else "" ) exact_gate = "" if status != "pass": @@ -445,15 +604,15 @@ def collect_state(args: argparse.Namespace, *, runner: Runner = subprocess_runne for key, value in checks.items() if value is not True ] - exact_gate = remote_stderr.strip() or ", ".join(failed) + exact_gate = "; ".join(part for part in (remote_stderr.strip(), ", ".join(failed)) if part) current_canary = ( "Read-only pre-send readiness for the exact three-turn unseen Leo chain in Telegram" if args.phase == "preflight" else "Read-only post-send DB grounding and unchanged-state proof for the exact Telegram chain" ) - return { + artifact = { "schema": SCHEMA, - "generated_at_utc": datetime.now(timezone.utc).isoformat(), + "generated_at_utc": generated_at_utc, "mode": "telegram_visible_unseen_chain_zero_mutation_state_readback", "phase": args.phase, "status": status, @@ -465,9 +624,11 @@ def collect_state(args: argparse.Namespace, *, runner: Runner = subprocess_runne "packet_path": str(args.packet), "packet_file_sha256": packet_file_sha256, "protocol_sha256": packet.get("protocol_sha256"), + "manifest_binding": packet.get("manifest_binding"), + "capture_challenge_nonce": capture_challenge_nonce, + "baseline_state_token_sha256": baseline_state_token_sha256, "baseline_path": str(args.baseline) if args.baseline else "", "subject_ref": args.subject_ref or "", - "state_token_sha256": state_token, "packet_checks": local_packet_checks, "remote_checks": remote_checks, "baseline_checks": baseline_checks, @@ -478,9 +639,15 @@ def collect_state(args: argparse.Namespace, *, runner: Runner = subprocess_runne "current_canary": current_canary, "attempted_routes": [ "local exact packet validation", - "SSH deploy stamp and gateway service readback", - "two canonical repeatable-read read-only Postgres parity manifests", - *(["independent selected-object DB readback"] if args.subject_ref else []), + *( + [ + "SSH deploy stamp and gateway service readback", + "two canonical repeatable-read read-only Postgres parity manifests", + *(["independent selected-object DB readback"] if args.subject_ref else []), + ] + if remote.get("readback_attempts") + else [] + ), ], "exact_gate": exact_gate, "clear_CTA": ( @@ -510,6 +677,8 @@ def collect_state(args: argparse.Namespace, *, runner: Runner = subprocess_runne ], }, } + artifact["state_token_sha256"] = derive_state_token(artifact) + return artifact def write_json(path: Path, data: dict[str, Any]) -> None: @@ -547,6 +716,10 @@ def write_markdown(path: Path, data: dict[str, Any]) -> None: f"- Deploy stamp: `{remote.get('last_deploy_sha', '')}`", f"- Gateway MainPID: `{service.get('MainPID', '')}`", f"- Gateway NRestarts: `{service.get('NRestarts', '')}`", + f"- Manifest: `{(data.get('manifest_binding') or {}).get('path', '')}`", + f"- Manifest SHA256: `{(data.get('manifest_binding') or {}).get('sha256', '')}`", + f"- Effective DB role: `{fingerprint.get('current_user', '')}`", + f"- Transaction read only: `{fingerprint.get('transaction_read_only', '')}`", f"- Canonical fingerprint: `{fingerprint.get('fingerprint_sha256', '')}`", f"- Canonical tables: `{fingerprint.get('table_count', '')}`", f"- Canonical rows: `{fingerprint.get('total_rows', '')}`", @@ -568,7 +741,6 @@ def parse_args(argv: list[str] | None = None) -> argparse.Namespace: parser.add_argument("--packet", type=Path, default=DEFAULT_PACKET) parser.add_argument("--baseline", type=Path) parser.add_argument("--subject-ref") - parser.add_argument("--manifest-sql", type=Path, default=DEFAULT_MANIFEST_SQL) parser.add_argument("--ssh-target", default=DEFAULT_SSH_TARGET) parser.add_argument("--ssh-key", type=Path, default=DEFAULT_SSH_KEY) parser.add_argument("--connect-timeout", type=int, default=10) diff --git a/scripts/verify_telegram_visible_unseen_chain.py b/scripts/verify_telegram_visible_unseen_chain.py index 8a92450..c754fc1 100644 --- a/scripts/verify_telegram_visible_unseen_chain.py +++ b/scripts/verify_telegram_visible_unseen_chain.py @@ -7,18 +7,30 @@ import argparse import hashlib import json import re +import struct +import zlib from datetime import datetime, timezone +from itertools import pairwise from pathlib import Path from typing import Any +from urllib.parse import urlparse try: import build_telegram_visible_unseen_chain_packet as packet_builder + import collect_telegram_visible_unseen_chain_state as state_collector import verify_leo_unseen_reasoning_chain as unseen except ImportError: # pragma: no cover - imported as scripts.* in tests from scripts import build_telegram_visible_unseen_chain_packet as packet_builder + from scripts import collect_telegram_visible_unseen_chain_state as state_collector from scripts import verify_leo_unseen_reasoning_chain as unseen -SCHEMA = "livingip.telegramVisibleUnseenChainReceipt.v1" +SCHEMA = "livingip.telegramVisibleUnseenChainReceipt.v2" +CAPTURE_SCHEMA = "livingip.telegramVisibleUnseenChainCapture.v1" +BROWSER_PROVENANCE_SCHEMA = "livingip.authenticatedChromeTelegramCaptureProvenance.v1" +SHA64_RE = re.compile(r"^[0-9a-f]{64}$") +MIN_SCREENSHOT_WIDTH = 320 +MIN_SCREENSHOT_HEIGHT = 200 +DEFAULT_CODEX_SESSIONS_ROOT = Path.home() / ".codex" / "sessions" REPORT_DIR = Path("docs/reports/leo-working-state-20260709") DEFAULT_PACKET = packet_builder.DEFAULT_OUT DEFAULT_PREFLIGHT = REPORT_DIR / "telegram-visible-unseen-chain-preflight-current.json" @@ -48,6 +60,7 @@ def _present(value: Any) -> bool: def blank_capture_template(packet: dict[str, Any], preflight: dict[str, Any]) -> dict[str, Any]: target = packet.get("target") or {} return { + "schema": CAPTURE_SCHEMA, "protocol_sha256": packet.get("protocol_sha256"), "preflight_state_token_sha256": preflight.get("state_token_sha256"), "operator_authorization_text": packet.get("explicit_operator_authorization_text"), @@ -62,6 +75,9 @@ def blank_capture_template(packet: dict[str, Any], preflight: dict[str, Any]) -> "captured_by": "", "final_screenshot": "", "final_accessibility": "", + "browser_provenance": "", + "final_capture_reuses_turn_3": False, + "final_capture_reuse_reason": "", }, "messages": [ { @@ -82,21 +98,137 @@ def blank_capture_template(packet: dict[str, Any], preflight: dict[str, Any]) -> def _resolve_evidence(path_value: str, evidence_root: Path) -> dict[str, Any]: + root = evidence_root.resolve() if not path_value.strip(): - return {"path": path_value, "exists": False, "bytes": 0, "sha256": ""} + return { + "path": path_value, + "exists": False, + "contained_in_evidence_root": False, + "bytes": 0, + "sha256": "", + } path = Path(path_value) if not path.is_absolute(): - path = evidence_root / path + path = root / path resolved = path.resolve() - exists = resolved.is_file() + contained = resolved == root or root in resolved.parents + exists = contained and resolved.is_file() return { "path": str(resolved), "exists": exists, + "contained_in_evidence_root": contained, "bytes": resolved.stat().st_size if exists else 0, "sha256": _sha256_file(resolved) if exists else "", } +def _inspect_png(evidence: dict[str, Any]) -> dict[str, Any]: + metadata: dict[str, Any] = { + "valid_png": False, + "width": 0, + "height": 0, + "bit_depth": 0, + "color_type": -1, + "crc_valid": False, + "pixel_data_valid": False, + } + if not evidence.get("exists"): + return metadata + data = Path(str(evidence["path"])).read_bytes() + if not data.startswith(b"\x89PNG\r\n\x1a\n"): + return metadata + offset = 8 + chunks: list[tuple[bytes, bytes]] = [] + crc_valid = True + while offset + 12 <= len(data): + length = struct.unpack(">I", data[offset : offset + 4])[0] + chunk_end = offset + 12 + length + if chunk_end > len(data): + return metadata + chunk_type = data[offset + 4 : offset + 8] + payload = data[offset + 8 : offset + 8 + length] + expected_crc = struct.unpack(">I", data[offset + 8 + length : chunk_end])[0] + crc_valid = crc_valid and (zlib.crc32(chunk_type + payload) & 0xFFFFFFFF) == expected_crc + chunks.append((chunk_type, payload)) + offset = chunk_end + if chunk_type == b"IEND": + break + if not chunks or chunks[0][0] != b"IHDR" or len(chunks[0][1]) != 13: + return metadata + if chunks[-1][0] != b"IEND" or offset != len(data): + return metadata + width, height, bit_depth, color_type, compression, filtering, interlace = struct.unpack(">IIBBBBB", chunks[0][1]) + idat = b"".join(payload for chunk_type, payload in chunks if chunk_type == b"IDAT") + channels = {2: 3, 6: 4}.get(color_type) + pixel_data_valid = False + if idat and channels and bit_depth == 8 and compression == 0 and filtering == 0 and interlace == 0: + try: + pixels = zlib.decompress(idat) + except zlib.error: + pixels = b"" + expected_size = height * (1 + width * channels) + pixel_data_valid = len(pixels) == expected_size + metadata.update( + { + "width": width, + "height": height, + "bit_depth": bit_depth, + "color_type": color_type, + "crc_valid": crc_valid, + "pixel_data_valid": pixel_data_valid, + "valid_png": crc_valid + and pixel_data_valid + and width >= MIN_SCREENSHOT_WIDTH + and height >= MIN_SCREENSHOT_HEIGHT, + } + ) + return metadata + + +def _parse_aware_timestamp(value: Any) -> datetime | None: + if not isinstance(value, str) or not value.strip(): + return None + candidate = value.strip() + if candidate.endswith("Z"): + candidate = candidate[:-1] + "+00:00" + try: + parsed = datetime.fromisoformat(candidate) + except ValueError: + return None + if parsed.tzinfo is None or parsed.utcoffset() is None: + return None + return parsed + + +def _all_true_section(value: Any, *, allow_empty: bool = False) -> bool: + if not isinstance(value, dict): + return False + return (allow_empty or bool(value)) and all(item is True for item in value.values()) + + +def _state_artifact_checks( + artifact: dict[str, Any], + *, + phase: str, + packet: dict[str, Any], + packet_path: Path, +) -> dict[str, bool]: + baseline_checks_required = phase == "postflight" + return { + f"{phase}_schema_supported": artifact.get("schema") == state_collector.SCHEMA, + f"{phase}_status_and_phase_pass": artifact.get("status") == "pass" and artifact.get("phase") == phase, + f"{phase}_packet_checks_all_pass": _all_true_section(artifact.get("packet_checks")), + f"{phase}_remote_checks_all_pass": _all_true_section(artifact.get("remote_checks")), + f"{phase}_baseline_checks_all_pass": _all_true_section( + artifact.get("baseline_checks"), allow_empty=not baseline_checks_required + ), + f"{phase}_state_token_derivation_valid": state_collector.state_token_is_valid(artifact), + f"{phase}_packet_file_hash_bound": artifact.get("packet_file_sha256") == _sha256_file(packet_path), + f"{phase}_protocol_bound": artifact.get("protocol_sha256") == packet.get("protocol_sha256"), + f"{phase}_manifest_bound": artifact.get("manifest_binding") == packet.get("manifest_binding"), + } + + def _capture_messages(capture: dict[str, Any]) -> list[dict[str, Any]]: messages = capture.get("messages") return [item for item in messages if isinstance(item, dict)] if isinstance(messages, list) else [] @@ -114,6 +246,378 @@ def _accessibility_binds_message(evidence: dict[str, Any], *, sent_text: str, re return _normalized_text(sent_text) in normalized and _normalized_text(reply) in normalized +def _artifact_hash_manifest( + *, + final_screenshot: dict[str, Any], + final_accessibility: dict[str, Any], + turn_evidence: list[dict[str, Any]], +) -> dict[str, Any]: + return { + "final_screenshot": final_screenshot.get("sha256"), + "final_accessibility": final_accessibility.get("sha256"), + "turn_screenshots": [item["screenshot"].get("sha256") for item in turn_evidence], + "turn_accessibility": [item["accessibility"].get("sha256") for item in turn_evidence], + } + + +def _browser_provenance_checks( + evidence: dict[str, Any], + *, + packet: dict[str, Any], + preflight: dict[str, Any], + capture: dict[str, Any], + capture_source: dict[str, Any], + messages: list[dict[str, Any]], + artifact_hashes: dict[str, Any], +) -> tuple[dict[str, bool], dict[str, Any]]: + provenance: dict[str, Any] = {} + if evidence.get("exists"): + try: + value = _load_json(Path(str(evidence["path"]))) + except (OSError, UnicodeDecodeError, json.JSONDecodeError): + value = {} + if isinstance(value, dict): + provenance = value + browser = provenance.get("browser") if isinstance(provenance.get("browser"), dict) else {} + authorization = provenance.get("authorization") if isinstance(provenance.get("authorization"), dict) else {} + telegram = provenance.get("telegram") if isinstance(provenance.get("telegram"), dict) else {} + provider_ids = [ + str(browser.get(key) or "") for key in ("browser_id", "session_id", "tab_id", "provider_capture_id") + ] + packet_serialized = json.dumps(packet, sort_keys=True) + provenance_serialized = json.dumps(provenance, sort_keys=True) + capture_serialized = json.dumps(capture, sort_keys=True) + target = packet.get("target") if isinstance(packet.get("target"), dict) else {} + page_url = str(browser.get("page_url") or "") + parsed_url = urlparse(page_url) + expected_message_ids = [str(item.get("telegram_message_id") or "") for item in messages] + expected_reply_ids = [str(item.get("reply_message_id") or "") for item in messages] + authorization_text = str(capture.get("operator_authorization_text") or "") + checks = { + "browser_provenance_file_present_and_contained": evidence.get("exists") is True + and evidence.get("contained_in_evidence_root") is True, + "browser_provenance_schema_supported": provenance.get("schema") == BROWSER_PROVENANCE_SCHEMA, + "browser_provenance_status_and_checks_pass": provenance.get("status") == "pass" + and _all_true_section(provenance.get("checks")), + "browser_provenance_channel_is_chrome_extension": provenance.get("capture_channel") == "codex_chrome_extension" + and browser.get("browser_type") == "extension", + "browser_provenance_sha256_not_self_declared": bool(evidence.get("sha256")) + and evidence.get("sha256") not in capture_serialized + and evidence.get("sha256") not in provenance_serialized, + "browser_provenance_challenge_and_protocol_bound": provenance.get("capture_challenge_nonce") + == preflight.get("capture_challenge_nonce") + and provenance.get("protocol_sha256") == packet.get("protocol_sha256"), + "browser_provider_identifiers_present_and_not_from_packet": all( + len(value) >= 8 and value not in packet_serialized for value in provider_ids + ) + and len(set(provider_ids)) == len(provider_ids), + "browser_observed_telegram_web_origin": parsed_url.scheme == "https" + and parsed_url.hostname == "web.telegram.org" + and str(target.get("chat_id") or "") in page_url, + "browser_observed_exact_chat_identity": telegram.get("chat_id") == target.get("chat_id") + and telegram.get("chat_label") == target.get("chat_label") + and str(target.get("chat_label") or "").casefold() in str(browser.get("page_title") or "").casefold(), + "browser_observed_exact_message_and_reply_ids": telegram.get("message_ids") == expected_message_ids + and telegram.get("reply_ids") == expected_reply_ids, + "browser_provenance_artifact_hashes_exact": provenance.get("artifacts") == artifact_hashes, + "browser_provenance_capture_timestamp_bound": browser.get("captured_at_utc") + == capture_source.get("captured_at_utc"), + "authorization_provenance_is_independent_codex_user_message": authorization.get("source") + == "codex_platform_user_message" + and all( + len(str(authorization.get(key) or "")) >= 8 for key in ("thread_id", "user_message_id", "source_receipt_id") + ), + "authorization_provenance_hash_and_timestamp_bound": authorization.get("text_sha256") + == hashlib.sha256(authorization_text.encode("utf-8")).hexdigest() + and authorization.get("captured_at_utc") == capture.get("operator_authorization_captured_at_utc"), + "authorization_text_not_copied_into_provenance": bool(authorization_text) + and authorization_text not in provenance_serialized, + } + return checks, provenance + + +def _codex_rollout_provenance_checks( + rollout_path: Path | None, + *, + sessions_root: Path, + evidence_root: Path, + packet: dict[str, Any], + capture: dict[str, Any], + provenance: dict[str, Any], + provenance_evidence: dict[str, Any], + artifact_hashes: dict[str, Any], + messages: list[dict[str, Any]], +) -> tuple[dict[str, bool], dict[str, Any]]: + root = sessions_root.resolve() + resolved = rollout_path.resolve() if rollout_path is not None else Path() + contained = bool(rollout_path) and resolved.is_file() and root in resolved.parents + outside_evidence_root = bool(rollout_path) and evidence_root.resolve() not in resolved.parents + events: list[dict[str, Any]] = [] + jsonl_valid = contained + if contained: + try: + with resolved.open(encoding="utf-8") as handle: + for line in handle: + if not line.strip(): + continue + value = json.loads(line) + if not isinstance(value, dict): + jsonl_valid = False + continue + events.append(value) + except (OSError, UnicodeDecodeError, json.JSONDecodeError): + jsonl_valid = False + events = [] + + operator_context = packet.get("operator_context") if isinstance(packet.get("operator_context"), dict) else {} + authorization = provenance.get("authorization") if isinstance(provenance.get("authorization"), dict) else {} + browser = provenance.get("browser") if isinstance(provenance.get("browser"), dict) else {} + thread_id = str(operator_context.get("codex_thread_id") or "") + authorization_text = str(capture.get("operator_authorization_text") or "") + user_message_id = str(authorization.get("user_message_id") or "") + matching_user_events: list[dict[str, Any]] = [] + browser_events: dict[str, dict[str, Any]] = {} + for event in events: + payload = event.get("payload") if isinstance(event.get("payload"), dict) else {} + if event.get("type") == "response_item" and payload.get("type") == "message" and payload.get("role") == "user": + content = payload.get("content") if isinstance(payload.get("content"), list) else [] + text = "".join( + str(item.get("text") or "") + for item in content + if isinstance(item, dict) and item.get("type") == "input_text" + ) + metadata = ( + payload.get("internal_chat_message_metadata_passthrough") + if isinstance(payload.get("internal_chat_message_metadata_passthrough"), dict) + else {} + ) + if text == authorization_text and metadata.get("turn_id") == user_message_id: + matching_user_events.append(event) + if event.get("type") == "event_msg" and payload.get("type") == "mcp_tool_call_end": + call_id = str(payload.get("call_id") or "") + if call_id: + browser_events[call_id] = event + + user_event = matching_user_events[0] if len(matching_user_events) == 1 else {} + session_meta_ids = [ + str((event.get("payload") or {}).get("id") or "") + for event in events + if event.get("type") == "session_meta" and isinstance(event.get("payload"), dict) + ] + user_event_sha256 = ( + hashlib.sha256(json.dumps(user_event, sort_keys=True, separators=(",", ":")).encode("utf-8")).hexdigest() + if user_event + else "" + ) + turn_call_ids = provenance.get("turn_capture_call_ids") + turn_call_ids = [str(value) for value in turn_call_ids] if isinstance(turn_call_ids, list) else [] + final_call_id = str(provenance.get("final_capture_call_id") or "") + reuse_final = (capture.get("capture_source") or {}).get("final_capture_reuses_turn_3") is True + call_id_shape_valid = ( + len(turn_call_ids) == 3 + and all(len(value) >= 8 for value in turn_call_ids) + and len(set(turn_call_ids)) == 3 + and len(final_call_id) >= 8 + and ( + (reuse_final and final_call_id == turn_call_ids[2]) + or (not reuse_final and final_call_id not in turn_call_ids) + ) + ) + expected_call_ids = set(turn_call_ids + ([final_call_id] if final_call_id else [])) + selected_events = {call_id: browser_events.get(call_id, {}) for call_id in expected_call_ids} + + def browser_event_parts(event: dict[str, Any]) -> tuple[dict[str, Any], str, datetime | None]: + payload = event.get("payload") if isinstance(event.get("payload"), dict) else {} + result = payload.get("result") if isinstance(payload.get("result"), dict) else {} + ok = result.get("Ok") if isinstance(result.get("Ok"), dict) else {} + meta = ok.get("_meta") if isinstance(ok.get("_meta"), dict) else {} + surface = meta.get("codex/toolSurface") if isinstance(meta.get("codex/toolSurface"), dict) else {} + content = ok.get("content") if isinstance(ok.get("content"), list) else [] + result_text = "\n".join( + str(item.get("text") or "") for item in content if isinstance(item, dict) and item.get("type") == "text" + ) + return surface, result_text, _parse_aware_timestamp(event.get("timestamp")) + + event_parts = {call_id: browser_event_parts(event) for call_id, event in selected_events.items()} + browser_id = str(browser.get("browser_id") or "") + tab_id = str(browser.get("tab_id") or "") + all_events_are_chrome = bool(expected_call_ids) and all( + event + and parts[0].get("backend") == "chrome" + and parts[0].get("kind") == "browserUse" + and parts[0].get("browserId") == browser_id + and tab_id in (parts[0].get("openTabIds") or []) + for call_id, event in selected_events.items() + for parts in [event_parts[call_id]] + ) + all_events_invoked_capture_apis = ( + bool(expected_call_ids) + and all( + event + and "screenshot(" + in str((((event.get("payload") or {}).get("invocation") or {}).get("arguments") or {}).get("code") or "") + and "domSnapshot(" + in str((((event.get("payload") or {}).get("invocation") or {}).get("arguments") or {}).get("code") or "") + and ".url(" + in str((((event.get("payload") or {}).get("invocation") or {}).get("arguments") or {}).get("code") or "") + and ".title(" + in str((((event.get("payload") or {}).get("invocation") or {}).get("arguments") or {}).get("code") or "") + for event in selected_events.values() + ) + and len(selected_events) == len(expected_call_ids) + ) + turn_receipts_bound = len(turn_call_ids) == len(messages) == 3 and all( + call_id in event_parts + and all( + value in event_parts[call_id][1] + for value in ( + artifact_hashes["turn_screenshots"][index], + artifact_hashes["turn_accessibility"][index], + str(message.get("telegram_message_id") or ""), + str(message.get("reply_message_id") or ""), + str(browser.get("page_url") or ""), + str(browser.get("page_title") or ""), + str((packet.get("target") or {}).get("chat_id") or ""), + ) + ) + for index, (call_id, message) in enumerate(zip(turn_call_ids, messages, strict=True)) + ) + final_receipt_text = event_parts.get(final_call_id, ({}, "", None))[1] + final_receipt_bound = bool(final_receipt_text) and all( + value in final_receipt_text + for value in ( + str(artifact_hashes.get("final_screenshot") or ""), + str(artifact_hashes.get("final_accessibility") or ""), + str(provenance_evidence.get("sha256") or ""), + *(str(item.get("telegram_message_id") or "") for item in messages), + *(str(item.get("reply_message_id") or "") for item in messages), + ) + ) + event_times = [event_parts.get(call_id, ({}, "", None))[2] for call_id in turn_call_ids] + final_event_at = event_parts.get(final_call_id, ({}, "", None))[2] + send_times = [_parse_aware_timestamp(item.get("sent_at_utc")) for item in messages] + reply_times = [_parse_aware_timestamp(item.get("reply_at_utc")) for item in messages] + browser_event_order_valid = all( + value is not None for value in (*event_times, final_event_at, *send_times, *reply_times) + ) + if browser_event_order_valid: + browser_event_order_valid = bool( + reply_times[0] < event_times[0] < send_times[1] + and reply_times[1] < event_times[1] < send_times[2] + and reply_times[2] < event_times[2] + and ( + (reuse_final and final_event_at == event_times[2]) + or (not reuse_final and event_times[2] < final_event_at) + ) + ) + authorization_event_at = _parse_aware_timestamp(user_event.get("timestamp")) if user_event else None + capture_source = capture.get("capture_source") if isinstance(capture.get("capture_source"), dict) else {} + checks = { + "codex_rollout_log_is_trusted_external_file": contained + and outside_evidence_root + and thread_id in resolved.name, + "codex_rollout_log_jsonl_valid": jsonl_valid and bool(events), + "codex_rollout_session_meta_matches_thread": session_meta_ids == [thread_id], + "codex_rollout_has_exact_single_authorization_event": len(matching_user_events) == 1, + "codex_authorization_event_bound_to_provenance": authorization.get("thread_id") == thread_id + and authorization.get("source_receipt_id") == user_event_sha256 + and user_event.get("timestamp") == capture.get("operator_authorization_captured_at_utc"), + "codex_rollout_capture_call_ids_valid": call_id_shape_valid, + "codex_rollout_capture_events_are_chrome_backend": all_events_are_chrome, + "codex_rollout_capture_events_invoked_screenshot_and_dom_snapshot": all_events_invoked_capture_apis, + "codex_rollout_turn_receipts_bind_artifacts_and_telegram_ids": turn_receipts_bound, + "codex_rollout_final_receipt_binds_provenance_artifacts_and_all_ids": final_receipt_bound, + "codex_rollout_capture_event_order_valid": browser_event_order_valid, + "codex_rollout_final_event_timestamp_bound": final_event_at is not None + and capture_source.get("captured_at_utc") == (selected_events.get(final_call_id) or {}).get("timestamp") + and browser.get("captured_at_utc") == (selected_events.get(final_call_id) or {}).get("timestamp"), + "codex_rollout_authorization_timestamp_is_aware": authorization_event_at is not None, + } + evidence = { + "path": str(resolved) if rollout_path else "", + "sha256": _sha256_file(resolved) if contained else "", + "thread_id": thread_id, + "authorization_turn_id": user_message_id, + "turn_capture_call_ids": turn_call_ids, + "final_capture_call_id": final_call_id, + "turn_capture_timestamps": [(selected_events.get(call_id) or {}).get("timestamp") for call_id in turn_call_ids], + "final_capture_timestamp": (selected_events.get(final_call_id) or {}).get("timestamp"), + } + return checks, evidence + + +def _timeline_checks( + preflight: dict[str, Any], + capture: dict[str, Any], + postflight: dict[str, Any], + provenance: dict[str, Any], + messages: list[dict[str, Any]], +) -> tuple[dict[str, bool], dict[str, Any]]: + capture_source = capture.get("capture_source") if isinstance(capture.get("capture_source"), dict) else {} + browser = provenance.get("browser") if isinstance(provenance.get("browser"), dict) else {} + authorization = provenance.get("authorization") if isinstance(provenance.get("authorization"), dict) else {} + preflight_at = _parse_aware_timestamp(preflight.get("generated_at_utc")) + authorization_at = _parse_aware_timestamp(capture.get("operator_authorization_captured_at_utc")) + send_times = [_parse_aware_timestamp(item.get("sent_at_utc")) for item in messages] + reply_times = [_parse_aware_timestamp(item.get("reply_at_utc")) for item in messages] + final_capture_at = _parse_aware_timestamp(capture_source.get("captured_at_utc")) + postflight_at = _parse_aware_timestamp(postflight.get("generated_at_utc")) + browser_capture_at = _parse_aware_timestamp(browser.get("captured_at_utc")) + authorization_provenance_at = _parse_aware_timestamp(authorization.get("captured_at_utc")) + timestamps = [ + preflight_at, + authorization_at, + *send_times, + *reply_times, + final_capture_at, + postflight_at, + browser_capture_at, + authorization_provenance_at, + ] + valid = len(messages) == 3 and all(value is not None for value in timestamps) + strict_turn_order = False + preflight_before_authorization = False + authorization_before_first_send = False + final_after_reply3 = False + postflight_after_reply3 = False + if valid: + assert preflight_at is not None + assert authorization_at is not None + assert final_capture_at is not None + assert postflight_at is not None + ordered_turns = [ + send_times[0], + reply_times[0], + send_times[1], + reply_times[1], + send_times[2], + reply_times[2], + ] + strict_turn_order = all(left < right for left, right in pairwise(ordered_turns)) + preflight_before_authorization = preflight_at < authorization_at + authorization_before_first_send = authorization_at < send_times[0] + final_after_reply3 = reply_times[2] < final_capture_at + postflight_after_reply3 = reply_times[2] < postflight_at + checks = { + "timestamps_valid_and_timezone_aware": valid, + "preflight_before_captured_authorization": preflight_before_authorization, + "captured_authorization_before_first_send": authorization_before_first_send, + "strict_send_reply_turn_order": strict_turn_order, + "final_capture_after_third_reply": final_after_reply3, + "postflight_after_third_reply": postflight_after_reply3, + } + timeline = { + "preflight": preflight.get("generated_at_utc"), + "authorization": capture.get("operator_authorization_captured_at_utc"), + "turns": [ + {"sent_at_utc": item.get("sent_at_utc"), "reply_at_utc": item.get("reply_at_utc")} for item in messages + ], + "final_capture": capture_source.get("captured_at_utc"), + "postflight": postflight.get("generated_at_utc"), + } + return checks, timeline + + def _subject_match(postflight: dict[str, Any]) -> dict[str, Any]: subject = (postflight.get("remote") or {}).get("subject_readback") or {} matches = subject.get("matches") if isinstance(subject, dict) else [] @@ -221,15 +725,25 @@ def verify_capture( *, packet_path: Path, evidence_root: Path, + codex_rollout_log: Path | None = None, + codex_sessions_root: Path = DEFAULT_CODEX_SESSIONS_ROOT, ) -> dict[str, Any]: if capture is None: + packet_integrity = state_collector.packet_checks(packet) + preflight_integrity = _state_artifact_checks( + preflight, + phase="preflight", + packet=packet, + packet_path=packet_path, + ) + ready = all(packet_integrity.values()) and all(preflight_integrity.values()) return { "schema": SCHEMA, "generated_at_utc": datetime.now(timezone.utc).isoformat(), "mode": "telegram_visible_unseen_chain_capture_verifier", - "status": "awaiting_action_time_authorization", + "status": "awaiting_action_time_authorization" if ready else "fail", "receipt_ready": False, - "current_tier": "T0_packet_plus_T3_preflight", + "current_tier": "T0_packet_plus_T3_preflight" if ready else "T0_failed_preflight", "required_tier": "T3_live_readonly", "telegram_visible_messages_sent": False, "mutates_db": False, @@ -238,14 +752,18 @@ def verify_capture( "postflight_path": str(DEFAULT_POSTFLIGHT), "capture_template": blank_capture_template(packet, preflight), "checks": { - "packet_ready": packet.get("ready_to_request_action_time_authorization") is True, - "preflight_passed": preflight.get("status") == "pass", + **packet_integrity, + **preflight_integrity, "action_time_authorization_present": False, "capture_present": False, "postflight_present": False, }, "claim_ceiling": { - "proven": "The exact packet and live zero-mutation preflight are ready.", + "proven": ( + "The exact packet and live zero-mutation preflight are ready." + if ready + else "No readiness claim; packet or preflight integrity validation failed." + ), "not_proven": [ "Telegram-visible message delivery", "Telegram-visible Leo replies", @@ -261,6 +779,7 @@ def verify_capture( ids = [str(item.get("telegram_message_id") or "") for item in messages] reply_ids = [str(item.get("reply_message_id") or "") for item in messages] screenshot = _resolve_evidence(str(capture_source.get("final_screenshot") or ""), evidence_root) + screenshot["png"] = _inspect_png(screenshot) accessibility = _resolve_evidence(str(capture_source.get("final_accessibility") or ""), evidence_root) turn_evidence = [ { @@ -270,6 +789,14 @@ def verify_capture( } for item in messages ] + for evidence in turn_evidence: + evidence["screenshot"]["png"] = _inspect_png(evidence["screenshot"]) + browser_provenance_evidence = _resolve_evidence(str(capture_source.get("browser_provenance") or ""), evidence_root) + artifact_hashes = _artifact_hash_manifest( + final_screenshot=screenshot, + final_accessibility=accessibility, + turn_evidence=turn_evidence, + ) postflight = postflight or {} subject_ref = str(postflight.get("subject_ref") or "") subject_match = _subject_match(postflight) @@ -285,23 +812,97 @@ def verify_capture( handler_path = evidence_root / handler_path expected_ids = [str(item.get("prompt_id") or "") for item in expected] actual_ids = [str(item.get("prompt_id") or "") for item in messages] + packet_integrity = state_collector.packet_checks(packet) + preflight_integrity = _state_artifact_checks( + preflight, + phase="preflight", + packet=packet, + packet_path=packet_path, + ) + postflight_integrity = _state_artifact_checks( + postflight, + phase="postflight", + packet=packet, + packet_path=packet_path, + ) + browser_checks, browser_provenance = _browser_provenance_checks( + browser_provenance_evidence, + packet=packet, + preflight=preflight, + capture=capture, + capture_source=capture_source, + messages=messages, + artifact_hashes=artifact_hashes, + ) + codex_rollout_checks, codex_rollout_evidence = _codex_rollout_provenance_checks( + codex_rollout_log, + sessions_root=codex_sessions_root, + evidence_root=evidence_root, + packet=packet, + capture=capture, + provenance=browser_provenance, + provenance_evidence=browser_provenance_evidence, + artifact_hashes=artifact_hashes, + messages=messages, + ) + timeline_checks, timeline = _timeline_checks( + preflight, + capture, + postflight, + browser_provenance, + messages, + ) + turn_screenshot_hashes = [item["screenshot"]["sha256"] for item in turn_evidence] + turn_accessibility_hashes = [item["accessibility"]["sha256"] for item in turn_evidence] + final_matches_earlier_turn = ( + screenshot.get("sha256") in turn_screenshot_hashes[:2] + or accessibility.get("sha256") in turn_accessibility_hashes[:2] + ) + final_matches_turn_three = bool( + len(turn_evidence) == 3 + and ( + screenshot.get("sha256") == turn_screenshot_hashes[2] + or accessibility.get("sha256") == turn_accessibility_hashes[2] + ) + ) + final_reuse_documented = capture_source.get("final_capture_reuses_turn_3") is True and _present( + capture_source.get("final_capture_reuse_reason") + ) + final_reuse_policy_satisfied = not final_matches_earlier_turn and ( + (final_matches_turn_three and final_reuse_documented) + or ( + not final_matches_turn_three + and capture_source.get("final_capture_reuses_turn_3") is False + and not _present(capture_source.get("final_capture_reuse_reason")) + ) + ) checks = { + **packet_integrity, + **preflight_integrity, + **postflight_integrity, + **browser_checks, + **codex_rollout_checks, + **timeline_checks, + "capture_schema_supported": capture.get("schema") == CAPTURE_SCHEMA, "packet_ready": packet.get("ready_to_request_action_time_authorization") is True, "packet_file_hash_matches_preflight": _sha256_file(packet_path) == preflight.get("packet_file_sha256"), "handler_receipt_binding_unchanged": handler_path.is_file() and _sha256_file(handler_path) == handler_binding.get("sha256"), - "preflight_passed": preflight.get("status") == "pass" and preflight.get("phase") == "preflight", - "postflight_passed": postflight.get("status") == "pass" and postflight.get("phase") == "postflight", "protocol_bound_across_all_artifacts": capture.get("protocol_sha256") == preflight.get("protocol_sha256") == postflight.get("protocol_sha256") == packet.get("protocol_sha256"), - "preflight_state_token_bound_to_capture": capture.get("preflight_state_token_sha256") - == preflight.get("state_token_sha256"), + "preflight_state_token_bound_to_capture_and_postflight": capture.get("preflight_state_token_sha256") + == preflight.get("state_token_sha256") + == postflight.get("baseline_state_token_sha256"), + "preflight_challenge_bound_to_postflight": bool( + SHA64_RE.fullmatch(str(preflight.get("capture_challenge_nonce") or "")) + ) + and preflight.get("capture_challenge_nonce") == postflight.get("capture_challenge_nonce"), "exact_action_time_authorization_captured": capture.get("operator_authorization_text") == packet.get("explicit_operator_authorization_text") and _present(capture.get("operator_authorization_captured_at_utc")), - "authenticated_chrome_transport_proven": capture_source.get("platform") == "telegram" + "authenticated_chrome_transport_declared": capture_source.get("platform") == "telegram" and capture_source.get("transport") == "authenticated_chrome_telegram_ui", "bot_api_not_substituted": "bot_api" not in json.dumps(capture_source).casefold(), "exact_destination_matches": capture_source.get("chat_label") == (packet.get("target") or {}).get("chat_label") @@ -315,13 +916,21 @@ def verify_capture( "message_and_reply_ids_present_unique": all(ids) and all(reply_ids) and len(set(ids)) == 3 - and len(set(reply_ids)) == 3, - "message_and_reply_timestamps_present": all( - _present(item.get("sent_at_utc")) and _present(item.get("reply_at_utc")) for item in messages - ), + and len(set(reply_ids)) == 3 + and set(ids).isdisjoint(reply_ids), "capture_metadata_present": all( _present(capture_source.get(key)) for key in ("captured_at_utc", "captured_by") ), + "all_evidence_paths_contained_in_root": all( + item.get("contained_in_evidence_root") is True + for item in ( + screenshot, + accessibility, + browser_provenance_evidence, + *(turn["screenshot"] for turn in turn_evidence), + *(turn["accessibility"] for turn in turn_evidence), + ) + ), "visual_evidence_files_present": screenshot["exists"] and screenshot["bytes"] > 0 and accessibility["exists"] @@ -334,6 +943,16 @@ def verify_capture( and item["accessibility"]["bytes"] > 0 for item in turn_evidence ), + "screenshots_are_valid_png_with_metadata": screenshot["png"]["valid_png"] is True + and len(turn_evidence) == 3 + and all(item["screenshot"]["png"]["valid_png"] is True for item in turn_evidence), + "per_turn_screenshot_hashes_distinct_nonempty": len(turn_screenshot_hashes) == 3 + and all(SHA64_RE.fullmatch(value) for value in turn_screenshot_hashes) + and len(set(turn_screenshot_hashes)) == 3, + "per_turn_accessibility_hashes_distinct_nonempty": len(turn_accessibility_hashes) == 3 + and all(SHA64_RE.fullmatch(value) for value in turn_accessibility_hashes) + and len(set(turn_accessibility_hashes)) == 3, + "final_capture_reuse_policy_satisfied": final_reuse_policy_satisfied, "turn_accessibility_binds_exact_messages_and_replies": len(turn_evidence) == len(messages) == 3 and all( _accessibility_binds_message( @@ -356,11 +975,26 @@ def verify_capture( "telegram_visible_three_turn_chain": all( checks[key] for key in ( - "authenticated_chrome_transport_proven", + "authenticated_chrome_transport_declared", + "browser_provenance_channel_is_chrome_extension", + "codex_rollout_has_exact_single_authorization_event", + "codex_rollout_capture_events_are_chrome_backend", + "codex_rollout_turn_receipts_bind_artifacts_and_telegram_ids", + "codex_rollout_final_receipt_binds_provenance_artifacts_and_all_ids", + "codex_rollout_capture_event_order_valid", + "browser_observed_telegram_web_origin", + "browser_observed_exact_chat_identity", + "browser_observed_exact_message_and_reply_ids", + "authorization_provenance_hash_and_timestamp_bound", "exact_destination_matches", "exact_three_messages_and_no_extras", "sent_text_exact", "visible_replies_nonempty", + "strict_send_reply_turn_order", + "screenshots_are_valid_png_with_metadata", + "per_turn_screenshot_hashes_distinct_nonempty", + "per_turn_accessibility_hashes_distinct_nonempty", + "final_capture_reuse_policy_satisfied", "visual_evidence_files_present", "turn_accessibility_binds_exact_messages_and_replies", ) @@ -396,7 +1030,8 @@ def verify_capture( "receipt_ready": passed, "current_tier": "T3_live_readonly" if passed else "T2_or_lower_incomplete_visible_proof", "required_tier": "T3_live_readonly", - "telegram_visible_messages_sent": True, + "telegram_visible_messages_sent": passed, + "capture_claimed_messages_sent": True, "production_apply_executed": False, "mutates_db": False, "packet_path": str(packet_path), @@ -411,6 +1046,12 @@ def verify_capture( "final_screenshot": screenshot, "final_accessibility": accessibility, "turn_evidence": turn_evidence, + "browser_provenance": browser_provenance_evidence, + "browser_provider_identifiers": browser_provenance.get("browser"), + "codex_rollout_provenance": codex_rollout_evidence, + "timeline": timeline, + "final_capture_reuses_turn_3": capture_source.get("final_capture_reuses_turn_3"), + "final_capture_reuse_reason": capture_source.get("final_capture_reuse_reason"), "telegram_message_ids": ids, "telegram_reply_ids": reply_ids, "preflight_state_token_sha256": preflight.get("state_token_sha256"), @@ -462,6 +1103,7 @@ def write_markdown(path: Path, data: dict[str, Any]) -> None: "## Awaiting Authorized Capture", "", "The packet and preflight are ready. No Telegram message has been sent by this verifier.", + "A future T3 receipt also requires the exact platform authorization event and Chrome-backend capture receipts from the bound Codex rollout log.", ] ) lines.extend( @@ -484,6 +1126,11 @@ def parse_args(argv: list[str] | None = None) -> argparse.Namespace: parser.add_argument("--capture-json", type=Path) parser.add_argument("--postflight", type=Path, default=DEFAULT_POSTFLIGHT) parser.add_argument("--evidence-root", type=Path, default=Path(".")) + parser.add_argument( + "--codex-rollout-log", + type=Path, + help="Platform rollout JSONL containing the exact user authorization and Chrome capture tool receipts", + ) parser.add_argument("--out", type=Path, default=DEFAULT_OUT) parser.add_argument("--markdown-out", type=Path, default=DEFAULT_MARKDOWN_OUT) return parser.parse_args(argv) @@ -502,6 +1149,7 @@ def main(argv: list[str] | None = None) -> int: postflight, packet_path=args.packet, evidence_root=args.evidence_root, + codex_rollout_log=args.codex_rollout_log, ) write_json(args.out, receipt) write_markdown(args.markdown_out, receipt) diff --git a/tests/test_build_telegram_visible_unseen_chain_packet.py b/tests/test_build_telegram_visible_unseen_chain_packet.py index 5a67f47..00160b3 100644 --- a/tests/test_build_telegram_visible_unseen_chain_packet.py +++ b/tests/test_build_telegram_visible_unseen_chain_packet.py @@ -22,6 +22,14 @@ def test_packet_binds_handler_receipt_and_preserves_exact_messages() -> None: assert all(len(item["message_sha256"]) == 64 for item in data["exact_messages"]) assert data["handler_receipt_binding"]["sha256"] == packet._sha256_file(packet.DEFAULT_HANDLER_RECEIPT) assert data["tooling_binding"] == packet.tooling_binding() + assert data["manifest_binding"] == packet.manifest_binding() + assert data["manifest_binding"]["path"] == "ops/postgres_parity_manifest.sql" + assert data["manifest_binding"]["execution_contract"]["effective_role"] == "pg_read_all_data" + assert data["manifest_binding"]["execution_contract"]["transaction_read_only"] == "on" + assert data["protocol"]["manifest_binding"] == data["manifest_binding"] + assert data["operator_context"]["codex_thread_id"] == packet.DEFAULT_CODEX_THREAD_ID + assert data["protocol"]["operator_context"] == data["operator_context"] + assert packet._canonical_sha256(data["protocol"]) == data["protocol_sha256"] assert all(data["checks"].values()) @@ -32,6 +40,7 @@ def test_action_time_authorization_contains_destination_transport_and_full_messa assert "Telegram group Leo (chat ID -5146042086)" in authorization assert "already-authenticated Chrome Telegram UI" in authorization assert "do not use the Bot API" in authorization + assert "Codex rollout's user-authorization and Chrome tool events" in authorization assert "no additional messages" in authorization for item in data["exact_messages"]: assert item["prompt_id"] in authorization diff --git a/tests/test_collect_telegram_visible_unseen_chain_state.py b/tests/test_collect_telegram_visible_unseen_chain_state.py index a53d59f..05366a3 100644 --- a/tests/test_collect_telegram_visible_unseen_chain_state.py +++ b/tests/test_collect_telegram_visible_unseen_chain_state.py @@ -5,6 +5,8 @@ import copy import json from pathlib import Path +import pytest + from scripts import build_telegram_visible_unseen_chain_packet as packet_builder from scripts import collect_telegram_visible_unseen_chain_state as state @@ -14,6 +16,7 @@ def manifest_output(*, row_count: int = 7) -> str: { "kind": "identity", "database": "teleo", + "current_user": packet_builder.READ_ONLY_DB_ROLE, "server_version_num": 160014, "server_encoding": "UTF8", "database_collation": "C.UTF-8", @@ -107,6 +110,10 @@ class GoodRunner: "", ) if "'subject_ref'" in input_text: + assert "default_transaction_read_only=on" in remote_command + assert "-c transaction_read_only=on" in remote_command + assert f"role={packet_builder.READ_ONLY_DB_ROLE}" in remote_command + assert "psql -X" in remote_command payload = { "subject_ref": "c0000000", "matches": [ @@ -119,6 +126,10 @@ class GoodRunner: } return state.CommandResult(0, f"BEGIN\n{json.dumps(payload)}\nROLLBACK\n", "") if "postgres_parity_manifest" not in remote_command and input_text.startswith("\\set ON_ERROR_STOP"): + assert "default_transaction_read_only=on" in remote_command + assert "-c transaction_read_only=on" in remote_command + assert f"role={packet_builder.READ_ONLY_DB_ROLE}" in remote_command + assert "psql -X" in remote_command return state.CommandResult(0, manifest_output(), "") raise AssertionError(f"unexpected command: {command} / input={input_text[:80]}") @@ -249,3 +260,61 @@ def test_subject_sql_rejects_untrusted_input() -> None: assert "subject_ref" in str(exc) else: raise AssertionError("unsafe subject ref was accepted") + + +class NoSshRunner: + def __init__(self) -> None: + self.calls = 0 + + def __call__(self, _command: list[str], _input_text: str, _timeout: int) -> state.CommandResult: + self.calls += 1 + raise AssertionError("SSH runner must not be called after local fail-closed rejection") + + +def test_write_capable_manifest_override_is_rejected_before_ssh(tmp_path: Path) -> None: + packet = write_packet(tmp_path) + malicious = tmp_path / "write.sql" + malicious.write_text( + "\\set ON_ERROR_STOP on\nbegin;\nupdate public.claims set status = 'live';\ncommit;\n", + encoding="utf-8", + ) + args = args_for(packet, tmp_path) + args.manifest_sql = malicious + runner = NoSshRunner() + + result = state.collect_state(args, runner=runner) + + assert result["status"] == "fail" + assert result["packet_checks"]["manifest_override_absent_or_exact_canonical_path"] is False + assert result["remote"]["readback_attempts"] == {} + assert runner.calls == 0 + assert state._manifest_sql_is_statically_read_only(malicious.read_text(encoding="utf-8")) is False + + +def test_manifest_hash_mismatch_is_rejected_before_ssh(tmp_path: Path) -> None: + packet_path = write_packet(tmp_path) + packet = json.loads(packet_path.read_text(encoding="utf-8")) + packet["manifest_binding"]["sha256"] = "0" * 64 + packet_path.write_text(json.dumps(packet), encoding="utf-8") + runner = NoSshRunner() + + result = state.collect_state(args_for(packet_path, tmp_path), runner=runner) + + assert result["status"] == "fail" + assert result["packet_checks"]["manifest_packet_sha256_matches_canonical_file"] is False + assert result["remote"]["readback_attempts"] == {} + assert runner.calls == 0 + + +def test_cli_removes_arbitrary_manifest_override() -> None: + with pytest.raises(SystemExit): + state.parse_args(["--manifest-sql", "write.sql"]) + + +def test_fingerprint_command_enforces_read_only_session_role_and_disables_psql_rc() -> None: + command = state.fingerprint_readback_command() + + assert "default_transaction_read_only=on" in command + assert "-c transaction_read_only=on" in command + assert f"role={packet_builder.READ_ONLY_DB_ROLE}" in command + assert "psql -X" in command diff --git a/tests/test_verify_telegram_visible_unseen_chain.py b/tests/test_verify_telegram_visible_unseen_chain.py index cbd6310..d70dc87 100644 --- a/tests/test_verify_telegram_visible_unseen_chain.py +++ b/tests/test_verify_telegram_visible_unseen_chain.py @@ -1,12 +1,22 @@ from __future__ import annotations import copy +import hashlib +import json +import struct +import zlib from pathlib import Path +import pytest + from scripts import build_telegram_visible_unseen_chain_packet as packet_builder +from scripts import collect_telegram_visible_unseen_chain_state as state_collector from scripts import verify_telegram_visible_unseen_chain as verifier SUBJECT_ID = "c0000000-0000-4000-8000-000000000001" +CHALLENGE_NONCE = "a" * 64 +TURN_CAPTURE_CALL_IDS = ["call_chrome_turn_1", "call_chrome_turn_2", "call_chrome_turn_3"] +FINAL_CAPTURE_CALL_ID = "call_chrome_final" def packet_and_path(tmp_path: Path) -> tuple[dict, Path]: @@ -19,56 +29,288 @@ def packet_and_path(tmp_path: Path) -> tuple[dict, Path]: return packet, path +def _finish_state_token(value: dict) -> dict: + value["state_token_sha256"] = state_collector.derive_state_token(value) + return value + + def preflight(packet: dict, packet_path: Path) -> dict: - return { - "phase": "preflight", - "status": "pass", - "protocol_sha256": packet["protocol_sha256"], - "packet_file_sha256": verifier._sha256_file(packet_path), - "state_token_sha256": "1" * 64, - "remote": { - "fingerprint_after": {"fingerprint_sha256": "f" * 64}, - "service_after": { - "MainPID": "123", - "NRestarts": "0", - "ExecMainStartTimestamp": "Wed 2026-07-15 00:00:00 UTC", + return _finish_state_token( + { + "schema": state_collector.SCHEMA, + "generated_at_utc": "2026-07-14T23:59:00+00:00", + "phase": "preflight", + "status": "pass", + "protocol_sha256": packet["protocol_sha256"], + "packet_file_sha256": verifier._sha256_file(packet_path), + "manifest_binding": packet["manifest_binding"], + "capture_challenge_nonce": CHALLENGE_NONCE, + "baseline_state_token_sha256": "", + "subject_ref": "", + "packet_checks": {"fixture_packet_checks_pass": True}, + "remote_checks": {"fixture_remote_checks_pass": True}, + "baseline_checks": {}, + "remote": { + "deploy_head": "d" * 40, + "last_deploy_sha": "d" * 40, + "fingerprint_after": {"fingerprint_sha256": "f" * 64}, + "service_after": { + "MainPID": "123", + "NRestarts": "0", + "ExecMainStartTimestamp": "Wed 2026-07-15 00:00:00 UTC", + }, + "subject_readback": None, }, + } + ) + + +def postflight(packet: dict, packet_path: Path, before: dict) -> dict: + return _finish_state_token( + { + "schema": state_collector.SCHEMA, + "generated_at_utc": "2026-07-15T00:04:00Z", + "phase": "postflight", + "status": "pass", + "protocol_sha256": packet["protocol_sha256"], + "packet_file_sha256": verifier._sha256_file(packet_path), + "manifest_binding": packet["manifest_binding"], + "capture_challenge_nonce": CHALLENGE_NONCE, + "baseline_state_token_sha256": before["state_token_sha256"], + "subject_ref": "c0000000", + "packet_checks": {"fixture_packet_checks_pass": True}, + "remote_checks": {"fixture_remote_checks_pass": True}, + "baseline_checks": {"fixture_baseline_checks_pass": True}, + "remote": { + "deploy_head": "d" * 40, + "last_deploy_sha": "d" * 40, + "fingerprint_after": {"fingerprint_sha256": "f" * 64}, + "service_after": { + "MainPID": "123", + "NRestarts": "0", + "ExecMainStartTimestamp": "Wed 2026-07-15 00:00:00 UTC", + }, + "subject_readback": { + "subject_ref": "c0000000", + "matches": [ + { + "table": "public.beliefs", + "row": {"id": SUBJECT_ID, "statement": "Coordination is the bottleneck."}, + } + ], + }, + }, + } + ) + + +def write_png(path: Path, rgba: tuple[int, int, int, int]) -> None: + width = verifier.MIN_SCREENSHOT_WIDTH + height = verifier.MIN_SCREENSHOT_HEIGHT + scanline = b"\x00" + bytes(rgba) * width + pixels = scanline * height + + def chunk(kind: bytes, payload: bytes) -> bytes: + return ( + struct.pack(">I", len(payload)) + + kind + + payload + + struct.pack(">I", zlib.crc32(kind + payload) & 0xFFFFFFFF) + ) + + ihdr = struct.pack(">IIBBBBB", width, height, 8, 6, 0, 0, 0) + path.write_bytes( + b"\x89PNG\r\n\x1a\n" + chunk(b"IHDR", ihdr) + chunk(b"IDAT", zlib.compress(pixels)) + chunk(b"IEND", b"") + ) + + +def _artifact_hashes(capture: dict) -> dict: + source = capture["capture_source"] + return { + "final_screenshot": verifier._sha256_file(Path(source["final_screenshot"])), + "final_accessibility": verifier._sha256_file(Path(source["final_accessibility"])), + "turn_screenshots": [verifier._sha256_file(Path(item["turn_screenshot"])) for item in capture["messages"]], + "turn_accessibility": [verifier._sha256_file(Path(item["turn_accessibility"])) for item in capture["messages"]], + } + + +def authorization_event(packet: dict, capture: dict) -> dict: + return { + "timestamp": capture["operator_authorization_captured_at_utc"], + "type": "response_item", + "payload": { + "type": "message", + "role": "user", + "content": [{"type": "input_text", "text": capture["operator_authorization_text"]}], + "internal_chat_message_metadata_passthrough": {"turn_id": "user-message-20260715-authorization"}, }, } -def postflight(packet: dict) -> dict: - return { - "phase": "postflight", +def write_browser_provenance(packet: dict, capture: dict, path: Path) -> str: + source = capture["capture_source"] + auth_event = authorization_event(packet, capture) + auth_event_sha256 = hashlib.sha256( + json.dumps(auth_event, sort_keys=True, separators=(",", ":")).encode("utf-8") + ).hexdigest() + final_call_id = TURN_CAPTURE_CALL_IDS[2] if source["final_capture_reuses_turn_3"] else FINAL_CAPTURE_CALL_ID + provenance = { + "schema": verifier.BROWSER_PROVENANCE_SCHEMA, "status": "pass", + "capture_channel": "codex_chrome_extension", + "capture_challenge_nonce": CHALLENGE_NONCE, "protocol_sha256": packet["protocol_sha256"], - "state_token_sha256": "2" * 64, - "subject_ref": "c0000000", - "remote": { - "fingerprint_after": {"fingerprint_sha256": "f" * 64}, - "service_after": { - "MainPID": "123", - "NRestarts": "0", - "ExecMainStartTimestamp": "Wed 2026-07-15 00:00:00 UTC", - }, - "subject_readback": { - "subject_ref": "c0000000", - "matches": [ - { - "table": "public.beliefs", - "row": {"id": SUBJECT_ID, "statement": "Coordination is the bottleneck."}, + "turn_capture_call_ids": TURN_CAPTURE_CALL_IDS, + "final_capture_call_id": final_call_id, + "browser": { + "browser_type": "extension", + "browser_id": "chrome-backend-20260715", + "session_id": "chrome-session-20260715", + "tab_id": "telegram-tab-20260715", + "provider_capture_id": "chrome-capture-20260715", + "page_url": "https://web.telegram.org/k/#-5146042086", + "page_title": "Leo - Telegram", + "captured_at_utc": source["captured_at_utc"], + }, + "authorization": { + "source": "codex_platform_user_message", + "thread_id": packet["operator_context"]["codex_thread_id"], + "user_message_id": "user-message-20260715-authorization", + "source_receipt_id": auth_event_sha256, + "text_sha256": hashlib.sha256(capture["operator_authorization_text"].encode("utf-8")).hexdigest(), + "captured_at_utc": capture["operator_authorization_captured_at_utc"], + }, + "telegram": { + "chat_label": "Leo", + "chat_id": "-5146042086", + "message_ids": [item["telegram_message_id"] for item in capture["messages"]], + "reply_ids": [item["reply_message_id"] for item in capture["messages"]], + }, + "artifacts": _artifact_hashes(capture), + "checks": { + "authenticated_chrome_extension_session": True, + "telegram_web_origin_observed": True, + "chat_identity_observed_in_browser": True, + "message_ids_observed_in_browser": True, + "accessibility_captured_from_browser": True, + "screenshots_captured_from_browser": True, + "authorization_read_from_codex_user_message": True, + }, + } + path.write_text(json.dumps(provenance, indent=2, sort_keys=True) + "\n", encoding="utf-8") + return verifier._sha256_file(path) + + +def write_codex_rollout(packet: dict, capture: dict, tmp_path: Path, provenance_sha256: str) -> Path: + provenance_path = Path(capture["capture_source"]["browser_provenance"]) + provenance = json.loads(provenance_path.read_text(encoding="utf-8")) + browser = provenance["browser"] + artifacts = provenance["artifacts"] + thread_id = packet["operator_context"]["codex_thread_id"] + sessions_root = tmp_path.parent / f"{tmp_path.name}-codex-sessions" + rollout_dir = sessions_root / "2026" / "07" / "15" + rollout_dir.mkdir(parents=True, exist_ok=True) + rollout_path = rollout_dir / f"rollout-2026-07-15T00-00-00-{thread_id}.jsonl" + events = [ + { + "timestamp": "2026-07-14T23:58:00Z", + "type": "session_meta", + "payload": {"id": thread_id}, + }, + authorization_event(packet, capture), + ] + + def chrome_event(call_id: str, timestamp: str, values: list[str]) -> dict: + return { + "timestamp": timestamp, + "type": "event_msg", + "payload": { + "type": "mcp_tool_call_end", + "call_id": call_id, + "invocation": { + "server": "node_repl", + "tool": "js", + "arguments": { + "code": ( + "await tab.screenshot({fullPage:false}); " + "await tab.playwright.domSnapshot(); await tab.url(); await tab.title();" + ) + }, + }, + "result": { + "Ok": { + "content": [{"type": "text", "text": json.dumps(values)}], + "isError": False, + "_meta": { + "codex/toolSurface": { + "backend": "chrome", + "browserId": browser["browser_id"], + "kind": "browserUse", + "openTabIds": [browser["tab_id"]], + } + }, } - ], + }, }, - }, - } + } + + turn_timestamps = ["2026-07-15T00:01:30Z", "2026-07-15T00:02:30Z", "2026-07-15T00:03:30Z"] + for index, (call_id, timestamp, message) in enumerate( + zip(TURN_CAPTURE_CALL_IDS, turn_timestamps, capture["messages"], strict=True) + ): + values = [ + artifacts["turn_screenshots"][index], + artifacts["turn_accessibility"][index], + message["telegram_message_id"], + message["reply_message_id"], + browser["page_url"], + browser["page_title"], + packet["target"]["chat_id"], + ] + if provenance["final_capture_call_id"] == call_id: + values.extend( + [ + artifacts["final_screenshot"], + artifacts["final_accessibility"], + provenance_sha256, + *[item["telegram_message_id"] for item in capture["messages"]], + *[item["reply_message_id"] for item in capture["messages"]], + ] + ) + timestamp = capture["capture_source"]["captured_at_utc"] + events.append(chrome_event(call_id, timestamp, values)) + if provenance["final_capture_call_id"] == FINAL_CAPTURE_CALL_ID: + events.append( + chrome_event( + FINAL_CAPTURE_CALL_ID, + capture["capture_source"]["captured_at_utc"], + [ + artifacts["final_screenshot"], + artifacts["final_accessibility"], + provenance_sha256, + *[item["telegram_message_id"] for item in capture["messages"]], + *[item["reply_message_id"] for item in capture["messages"]], + ], + ) + ) + rollout_path.write_text( + "".join(json.dumps(event, sort_keys=True) + "\n" for event in events), + encoding="utf-8", + ) + return rollout_path -def good_capture(packet: dict, tmp_path: Path) -> dict: +def refresh_provenance_and_rollout(packet: dict, capture: dict, tmp_path: Path) -> Path: + provenance_path = Path(capture["capture_source"]["browser_provenance"]) + provenance_sha256 = write_browser_provenance(packet, capture, provenance_path) + return write_codex_rollout(packet, capture, tmp_path, provenance_sha256) + + +def good_capture(packet: dict, tmp_path: Path) -> tuple[dict, Path]: screenshot = tmp_path / "final.png" accessibility = tmp_path / "final.txt" - screenshot.write_bytes(b"png proof") - accessibility.write_text("telegram accessibility proof", encoding="utf-8") + write_png(screenshot, (10, 20, 30, 255)) + accessibility.write_text("telegram final accessibility proof", encoding="utf-8") replies = [ ( "The database public.beliefs object c0000000 is an axiom with confidence 0.85. What supports it in " @@ -85,12 +327,13 @@ def good_capture(packet: dict, tmp_path: Path) -> dict: "review; approved is not apply and applied_at remains null. This is not an apply." ), ] + colors = [(40, 50, 60, 255), (70, 80, 90, 255), (100, 110, 120, 255)] messages = [] - for item, reply in zip(packet["exact_messages"], replies, strict=True): + for item, reply, color in zip(packet["exact_messages"], replies, colors, strict=True): sequence = item["sequence"] turn_screenshot = tmp_path / f"turn-{sequence}.png" turn_accessibility = tmp_path / f"turn-{sequence}.txt" - turn_screenshot.write_bytes(f"turn {sequence} screenshot".encode()) + write_png(turn_screenshot, color) turn_accessibility.write_text( f"Telegram message: {item['message']}\nLeo reply: {reply}\n", encoding="utf-8", @@ -109,7 +352,307 @@ def good_capture(packet: dict, tmp_path: Path) -> dict: "turn_accessibility": str(turn_accessibility), } ) - return { + provenance_path = tmp_path / "browser-provenance.json" + capture = { + "schema": verifier.CAPTURE_SCHEMA, + "protocol_sha256": packet["protocol_sha256"], + "preflight_state_token_sha256": "", + "operator_authorization_text": packet["explicit_operator_authorization_text"], + "operator_authorization_captured_at_utc": "2026-07-15T00:00:00Z", + "extra_messages_sent": 0, + "capture_source": { + "platform": "telegram", + "transport": "authenticated_chrome_telegram_ui", + "chat_label": "Leo", + "chat_id": "-5146042086", + "captured_at_utc": "2026-07-15T00:03:40Z", + "captured_by": "codex_chrome_extension", + "final_screenshot": str(screenshot), + "final_accessibility": str(accessibility), + "browser_provenance": str(provenance_path), + "final_capture_reuses_turn_3": False, + "final_capture_reuse_reason": "", + }, + "messages": messages, + } + rollout_path = refresh_provenance_and_rollout(packet, capture, tmp_path) + return capture, rollout_path + + +def verified_fixture(tmp_path: Path) -> tuple[dict, Path, dict, dict, dict, Path]: + packet, packet_path = packet_and_path(tmp_path) + before = preflight(packet, packet_path) + after = postflight(packet, packet_path, before) + capture, trusted_sha256 = good_capture(packet, tmp_path) + capture["preflight_state_token_sha256"] = before["state_token_sha256"] + return packet, packet_path, before, after, capture, trusted_sha256 + + +def run_verifier( + packet: dict, + packet_path: Path, + before: dict, + after: dict, + capture: dict, + rollout_log: Path | None, + tmp_path: Path, +) -> dict: + return verifier.verify_capture( + packet, + before, + capture, + after, + packet_path=packet_path, + evidence_root=tmp_path, + codex_rollout_log=rollout_log, + codex_sessions_root=( + rollout_log.parents[3] if rollout_log is not None else tmp_path.parent / f"{tmp_path.name}-codex-sessions" + ), + ) + + +def test_no_capture_returns_awaiting_authorization_template(tmp_path: Path) -> None: + packet, packet_path = packet_and_path(tmp_path) + before = preflight(packet, packet_path) + + receipt = verifier.verify_capture( + packet, + before, + None, + None, + packet_path=packet_path, + evidence_root=tmp_path, + ) + + assert receipt["status"] == "awaiting_action_time_authorization" + assert receipt["telegram_visible_messages_sent"] is False + assert receipt["capture_template"]["schema"] == verifier.CAPTURE_SCHEMA + assert receipt["capture_template"]["messages"][0]["prompt_id"] == "OOS-CHAIN-01" + + +def test_good_chrome_capture_and_unchanged_fingerprint_pass_t3(tmp_path: Path) -> None: + packet, packet_path, before, after, capture, trusted = verified_fixture(tmp_path) + + receipt = run_verifier(packet, packet_path, before, after, capture, trusted, tmp_path) + + assert receipt["status"] == "pass" + assert receipt["receipt_ready"] is True + assert receipt["current_tier"] == "T3_live_readonly" + assert all(receipt["checks"].values()) + assert all(receipt["outcomes"].values()) + assert receipt["selected_subject"]["row_id"] == SUBJECT_ID + + +def test_self_declared_browser_provenance_without_codex_rollout_cannot_pass_t3( + tmp_path: Path, +) -> None: + packet, packet_path, before, after, capture, _rollout = verified_fixture(tmp_path) + + receipt = run_verifier(packet, packet_path, before, after, capture, None, tmp_path) + + assert receipt["status"] == "fail" + assert receipt["telegram_visible_messages_sent"] is False + assert receipt["checks"]["codex_rollout_log_is_trusted_external_file"] is False + assert receipt["checks"]["codex_rollout_capture_events_are_chrome_backend"] is False + + +def test_non_chrome_rollout_capture_events_are_rejected(tmp_path: Path) -> None: + packet, packet_path, before, after, capture, rollout = verified_fixture(tmp_path) + events = [json.loads(line) for line in rollout.read_text(encoding="utf-8").splitlines()] + for event in events: + payload = event.get("payload") or {} + if payload.get("type") == "mcp_tool_call_end": + payload["result"]["Ok"]["_meta"]["codex/toolSurface"]["backend"] = "computerUse" + rollout.write_text( + "".join(json.dumps(event, sort_keys=True) + "\n" for event in events), + encoding="utf-8", + ) + + receipt = run_verifier(packet, packet_path, before, after, capture, rollout, tmp_path) + + assert receipt["status"] == "fail" + assert receipt["checks"]["codex_rollout_capture_events_are_chrome_backend"] is False + + +def test_bot_api_capture_is_rejected(tmp_path: Path) -> None: + packet, packet_path, before, after, capture, trusted = verified_fixture(tmp_path) + capture["capture_source"]["transport"] = "telegram_bot_api" + + receipt = run_verifier(packet, packet_path, before, after, capture, trusted, tmp_path) + + assert receipt["status"] == "fail" + assert receipt["checks"]["authenticated_chrome_transport_declared"] is False + assert receipt["checks"]["bot_api_not_substituted"] is False + + +def test_postflight_fingerprint_drift_is_rejected(tmp_path: Path) -> None: + packet, packet_path, before, after, capture, trusted = verified_fixture(tmp_path) + after["remote"]["fingerprint_after"]["fingerprint_sha256"] = "0" * 64 + + receipt = run_verifier(packet, packet_path, before, after, capture, trusted, tmp_path) + + assert receipt["status"] == "fail" + assert receipt["checks"]["postflight_state_token_derivation_valid"] is False + assert receipt["checks"]["canonical_fingerprint_unchanged_from_preflight"] is False + + +def test_message_text_drift_is_rejected(tmp_path: Path) -> None: + packet, packet_path, before, after, capture, trusted = verified_fixture(tmp_path) + capture["messages"][1]["sent_text"] += " extra" + + receipt = run_verifier(packet, packet_path, before, after, capture, trusted, tmp_path) + + assert receipt["status"] == "fail" + assert receipt["checks"]["sent_text_exact"] is False + + +def test_sent_and_reply_message_id_reuse_is_rejected(tmp_path: Path) -> None: + packet, packet_path, before, after, capture, _rollout = verified_fixture(tmp_path) + capture["messages"][0]["reply_message_id"] = capture["messages"][0]["telegram_message_id"] + rollout = refresh_provenance_and_rollout(packet, capture, tmp_path) + + receipt = run_verifier(packet, packet_path, before, after, capture, rollout, tmp_path) + + assert receipt["status"] == "fail" + assert receipt["checks"]["message_and_reply_ids_present_unique"] is False + + +def test_copied_reply_not_present_in_accessibility_is_rejected(tmp_path: Path) -> None: + packet, packet_path, before, after, capture, trusted = verified_fixture(tmp_path) + capture["messages"][0]["reply"] += " copied-only suffix" + + receipt = run_verifier(packet, packet_path, before, after, capture, trusted, tmp_path) + + assert receipt["status"] == "fail" + assert receipt["checks"]["turn_accessibility_binds_exact_messages_and_replies"] is False + + +def test_all_prompts_sent_before_replies_is_rejected(tmp_path: Path) -> None: + packet, packet_path, before, after, capture, trusted = verified_fixture(tmp_path) + capture["messages"][0]["reply_at_utc"] = "2026-07-15T00:02:30Z" + + receipt = run_verifier(packet, packet_path, before, after, capture, trusted, tmp_path) + + assert receipt["status"] == "fail" + assert receipt["checks"]["strict_send_reply_turn_order"] is False + + +def test_after_the_fact_authorization_is_rejected(tmp_path: Path) -> None: + packet, packet_path, before, after, capture, _trusted = verified_fixture(tmp_path) + capture["operator_authorization_captured_at_utc"] = "2026-07-15T00:01:10Z" + trusted = refresh_provenance_and_rollout(packet, capture, tmp_path) + + receipt = run_verifier(packet, packet_path, before, after, capture, trusted, tmp_path) + + assert receipt["status"] == "fail" + assert receipt["checks"]["captured_authorization_before_first_send"] is False + + +@pytest.mark.parametrize("timestamp", ["2026-07-15T00:01:00", "not-a-timestamp"]) +def test_naive_or_malformed_timestamps_are_rejected(tmp_path: Path, timestamp: str) -> None: + packet, packet_path, before, after, capture, trusted = verified_fixture(tmp_path) + capture["messages"][0]["sent_at_utc"] = timestamp + + receipt = run_verifier(packet, packet_path, before, after, capture, trusted, tmp_path) + + assert receipt["status"] == "fail" + assert receipt["checks"]["timestamps_valid_and_timezone_aware"] is False + + +def test_reused_per_turn_evidence_is_rejected(tmp_path: Path) -> None: + packet, packet_path, before, after, capture, _trusted = verified_fixture(tmp_path) + capture["messages"][1]["turn_screenshot"] = capture["messages"][0]["turn_screenshot"] + capture["messages"][1]["turn_accessibility"] = capture["messages"][0]["turn_accessibility"] + trusted = refresh_provenance_and_rollout(packet, capture, tmp_path) + + receipt = run_verifier(packet, packet_path, before, after, capture, trusted, tmp_path) + + assert receipt["status"] == "fail" + assert receipt["checks"]["per_turn_screenshot_hashes_distinct_nonempty"] is False + assert receipt["checks"]["per_turn_accessibility_hashes_distinct_nonempty"] is False + + +def test_final_capture_may_reuse_turn_three_when_documented(tmp_path: Path) -> None: + packet, packet_path, before, after, capture, _trusted = verified_fixture(tmp_path) + capture["capture_source"]["final_screenshot"] = capture["messages"][2]["turn_screenshot"] + capture["capture_source"]["final_accessibility"] = capture["messages"][2]["turn_accessibility"] + capture["capture_source"]["final_capture_reuses_turn_3"] = True + capture["capture_source"]["final_capture_reuse_reason"] = ( + "The final Chrome capture is the retained third-turn response state." + ) + trusted = refresh_provenance_and_rollout(packet, capture, tmp_path) + + receipt = run_verifier(packet, packet_path, before, after, capture, trusted, tmp_path) + + assert receipt["status"] == "pass" + assert receipt["checks"]["final_capture_reuse_policy_satisfied"] is True + + +def test_undocumented_final_turn_three_reuse_is_rejected(tmp_path: Path) -> None: + packet, packet_path, before, after, capture, _trusted = verified_fixture(tmp_path) + capture["capture_source"]["final_screenshot"] = capture["messages"][2]["turn_screenshot"] + trusted = refresh_provenance_and_rollout(packet, capture, tmp_path) + + receipt = run_verifier(packet, packet_path, before, after, capture, trusted, tmp_path) + + assert receipt["status"] == "fail" + assert receipt["checks"]["final_capture_reuse_policy_satisfied"] is False + + +def test_evidence_path_escape_is_rejected(tmp_path: Path) -> None: + packet, packet_path, before, after, capture, trusted = verified_fixture(tmp_path) + outside = tmp_path.parent / "outside-turn.png" + write_png(outside, (1, 2, 3, 255)) + capture["messages"][0]["turn_screenshot"] = str(outside) + + receipt = run_verifier(packet, packet_path, before, after, capture, trusted, tmp_path) + + assert receipt["status"] == "fail" + assert receipt["checks"]["all_evidence_paths_contained_in_root"] is False + + +def test_non_png_screenshot_is_rejected(tmp_path: Path) -> None: + packet, packet_path, before, after, capture, _trusted = verified_fixture(tmp_path) + Path(capture["messages"][0]["turn_screenshot"]).write_bytes(b"not a png") + trusted = refresh_provenance_and_rollout(packet, capture, tmp_path) + + receipt = run_verifier(packet, packet_path, before, after, capture, trusted, tmp_path) + + assert receipt["status"] == "fail" + assert receipt["checks"]["screenshots_are_valid_png_with_metadata"] is False + + +def test_fabricated_local_bundle_without_supported_state_or_trusted_chrome_provenance_fails( + tmp_path: Path, +) -> None: + packet, packet_path = packet_and_path(tmp_path) + before = { + "phase": "preflight", + "status": "pass", + "generated_at_utc": "2026-07-14T23:59:00Z", + "protocol_sha256": packet["protocol_sha256"], + "packet_file_sha256": verifier._sha256_file(packet_path), + "state_token_sha256": "1" * 64, + "remote": {"fingerprint_after": {"fingerprint_sha256": "f" * 64}, "service_after": {}}, + } + after = { + "phase": "postflight", + "status": "pass", + "generated_at_utc": "2026-07-15T00:04:00Z", + "protocol_sha256": packet["protocol_sha256"], + "state_token_sha256": "2" * 64, + "subject_ref": "c0000000", + "remote": { + "fingerprint_after": {"fingerprint_sha256": "f" * 64}, + "service_after": {}, + "subject_readback": {"subject_ref": "c0000000", "matches": []}, + }, + } + fake_png = tmp_path / "fake.png" + fake_text = tmp_path / "fake.txt" + fake_png.write_bytes(b"arbitrary non-PNG bytes") + fake_text.write_text("copied prompts and replies", encoding="utf-8") + capture = { "protocol_sha256": packet["protocol_sha256"], "preflight_state_token_sha256": "1" * 64, "operator_authorization_text": packet["explicit_operator_authorization_text"], @@ -120,121 +663,51 @@ def good_capture(packet: dict, tmp_path: Path) -> dict: "transport": "authenticated_chrome_telegram_ui", "chat_label": "Leo", "chat_id": "-5146042086", - "captured_at_utc": "2026-07-15T00:05:00Z", - "captured_by": "codex", - "final_screenshot": str(screenshot), - "final_accessibility": str(accessibility), + "captured_at_utc": "2026-07-15T00:03:40Z", + "captured_by": "fabricated", + "final_screenshot": str(fake_png), + "final_accessibility": str(fake_text), + "browser_provenance": "", + "final_capture_reuses_turn_3": False, + "final_capture_reuse_reason": "", }, - "messages": messages, + "messages": [ + { + "sequence": item["sequence"], + "prompt_id": item["prompt_id"], + "sent_text": item["message"], + "reply": f"fabricated reply {item['sequence']}", + "sent_at_utc": f"2026-07-15T00:0{item['sequence']}:00Z", + "reply_at_utc": f"2026-07-15T00:0{item['sequence']}:20Z", + "telegram_message_id": f"sent-{item['sequence']}", + "reply_message_id": f"reply-{item['sequence']}", + "turn_screenshot": str(fake_png), + "turn_accessibility": str(fake_text), + } + for item in packet["exact_messages"] + ], } + receipt = run_verifier(packet, packet_path, before, after, capture, None, tmp_path) -def test_no_capture_returns_awaiting_authorization_template(tmp_path: Path) -> None: - packet, packet_path = packet_and_path(tmp_path) - - receipt = verifier.verify_capture( - packet, - preflight(packet, packet_path), - None, - None, - packet_path=packet_path, - evidence_root=tmp_path, - ) - - assert receipt["status"] == "awaiting_action_time_authorization" + assert receipt["status"] == "fail" + assert receipt["current_tier"] != "T3_live_readonly" assert receipt["telegram_visible_messages_sent"] is False - assert receipt["capture_template"]["messages"][0]["prompt_id"] == "OOS-CHAIN-01" + assert receipt["checks"]["capture_schema_supported"] is False + assert receipt["checks"]["preflight_schema_supported"] is False + assert receipt["checks"]["preflight_state_token_derivation_valid"] is False + assert receipt["checks"]["codex_rollout_log_is_trusted_external_file"] is False + assert receipt["checks"]["codex_rollout_has_exact_single_authorization_event"] is False + assert receipt["checks"]["screenshots_are_valid_png_with_metadata"] is False + assert receipt["checks"]["per_turn_screenshot_hashes_distinct_nonempty"] is False -def test_good_chrome_capture_and_unchanged_fingerprint_pass_t3(tmp_path: Path) -> None: - packet, packet_path = packet_and_path(tmp_path) - before = preflight(packet, packet_path) +def test_state_token_tampering_is_rejected(tmp_path: Path) -> None: + packet, packet_path, before, after, capture, trusted = verified_fixture(tmp_path) + before = copy.deepcopy(before) + before["generated_at_utc"] = "2026-07-14T23:58:00Z" - receipt = verifier.verify_capture( - packet, - before, - good_capture(packet, tmp_path), - postflight(packet), - packet_path=packet_path, - evidence_root=tmp_path, - ) - - assert receipt["status"] == "pass" - assert receipt["receipt_ready"] is True - assert receipt["current_tier"] == "T3_live_readonly" - assert all(receipt["checks"].values()) - assert all(receipt["outcomes"].values()) - assert receipt["selected_subject"]["row_id"] == SUBJECT_ID - - -def test_bot_api_capture_is_rejected(tmp_path: Path) -> None: - packet, packet_path = packet_and_path(tmp_path) - capture = good_capture(packet, tmp_path) - capture["capture_source"]["transport"] = "telegram_bot_api" - - receipt = verifier.verify_capture( - packet, - preflight(packet, packet_path), - capture, - postflight(packet), - packet_path=packet_path, - evidence_root=tmp_path, - ) + receipt = run_verifier(packet, packet_path, before, after, capture, trusted, tmp_path) assert receipt["status"] == "fail" - assert receipt["checks"]["authenticated_chrome_transport_proven"] is False - assert receipt["checks"]["bot_api_not_substituted"] is False - - -def test_postflight_fingerprint_drift_is_rejected(tmp_path: Path) -> None: - packet, packet_path = packet_and_path(tmp_path) - after = copy.deepcopy(postflight(packet)) - after["remote"]["fingerprint_after"]["fingerprint_sha256"] = "0" * 64 - - receipt = verifier.verify_capture( - packet, - preflight(packet, packet_path), - good_capture(packet, tmp_path), - after, - packet_path=packet_path, - evidence_root=tmp_path, - ) - - assert receipt["status"] == "fail" - assert receipt["checks"]["canonical_fingerprint_unchanged_from_preflight"] is False - - -def test_message_text_drift_is_rejected(tmp_path: Path) -> None: - packet, packet_path = packet_and_path(tmp_path) - capture = good_capture(packet, tmp_path) - capture["messages"][1]["sent_text"] += " extra" - - receipt = verifier.verify_capture( - packet, - preflight(packet, packet_path), - capture, - postflight(packet), - packet_path=packet_path, - evidence_root=tmp_path, - ) - - assert receipt["status"] == "fail" - assert receipt["checks"]["sent_text_exact"] is False - - -def test_copied_reply_not_present_in_accessibility_is_rejected(tmp_path: Path) -> None: - packet, packet_path = packet_and_path(tmp_path) - capture = good_capture(packet, tmp_path) - capture["messages"][0]["reply"] += " copied-only suffix" - - receipt = verifier.verify_capture( - packet, - preflight(packet, packet_path), - capture, - postflight(packet), - packet_path=packet_path, - evidence_root=tmp_path, - ) - - assert receipt["status"] == "fail" - assert receipt["checks"]["turn_accessibility_binds_exact_messages_and_replies"] is False + assert receipt["checks"]["preflight_state_token_derivation_valid"] is False From 35c9531950b4d333782d253454c6aebef1e883c3 Mon Sep 17 00:00:00 2001 From: twentyOne2x Date: Wed, 15 Jul 2026 06:17:20 +0200 Subject: [PATCH 3/3] fix: make local Telegram verification preparation-only --- .../verify_telegram_visible_unseen_chain.py | 106 ++++++++----- ...st_verify_telegram_visible_unseen_chain.py | 141 ++++++++++++------ 2 files changed, 164 insertions(+), 83 deletions(-) diff --git a/scripts/verify_telegram_visible_unseen_chain.py b/scripts/verify_telegram_visible_unseen_chain.py index c754fc1..33cd526 100644 --- a/scripts/verify_telegram_visible_unseen_chain.py +++ b/scripts/verify_telegram_visible_unseen_chain.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -"""Verify retained authenticated-Chrome proof for Leo's unseen Telegram chain.""" +"""Validate local Telegram capture structure without authenticating live delivery.""" from __future__ import annotations @@ -24,12 +24,15 @@ except ImportError: # pragma: no cover - imported as scripts.* in tests from scripts import collect_telegram_visible_unseen_chain_state as state_collector from scripts import verify_leo_unseen_reasoning_chain as unseen -SCHEMA = "livingip.telegramVisibleUnseenChainReceipt.v2" +SCHEMA = "livingip.telegramVisibleUnseenChainReceipt.v3" CAPTURE_SCHEMA = "livingip.telegramVisibleUnseenChainCapture.v1" BROWSER_PROVENANCE_SCHEMA = "livingip.authenticatedChromeTelegramCaptureProvenance.v1" SHA64_RE = re.compile(r"^[0-9a-f]{64}$") MIN_SCREENSHOT_WIDTH = 320 MIN_SCREENSHOT_HEIGHT = 200 +PREPARATION_STATUS = "prepared_external_receipt_required" +PREPARATION_TIER = "T0_local_preparation" +FAILED_PREPARATION_TIER = "T0_failed_preparation" DEFAULT_CODEX_SESSIONS_ROOT = Path.home() / ".codex" / "sessions" REPORT_DIR = Path("docs/reports/leo-working-state-20260709") DEFAULT_PACKET = packet_builder.DEFAULT_OUT @@ -57,6 +60,24 @@ def _present(value: Any) -> bool: return True +def _preparation_only_fields(*, preparation_ready: bool) -> dict[str, Any]: + return { + "verification_scope": "caller_writable_preparation_structure", + "preparation_ready": preparation_ready, + "receipt_ready": False, + "current_tier": PREPARATION_TIER if preparation_ready else FAILED_PREPARATION_TIER, + "required_tier": "T3_live_readonly", + "telegram_visible_messages_sent": False, + "live_receipt_boundary": { + "required": True, + "verified": False, + "accepted_by_this_api": False, + "authority": "independently_authenticated_platform_browser_receipt", + "local_inputs_are": "caller_writable_preparation_evidence", + }, + } + + def blank_capture_template(packet: dict[str, Any], preflight: dict[str, Any]) -> dict[str, Any]: target = packet.get("target") or {} return { @@ -322,7 +343,7 @@ def _browser_provenance_checks( "browser_provenance_artifact_hashes_exact": provenance.get("artifacts") == artifact_hashes, "browser_provenance_capture_timestamp_bound": browser.get("captured_at_utc") == capture_source.get("captured_at_utc"), - "authorization_provenance_is_independent_codex_user_message": authorization.get("source") + "authorization_provenance_claim_has_codex_user_message_shape": authorization.get("source") == "codex_platform_user_message" and all( len(str(authorization.get(key) or "")) >= 8 for key in ("thread_id", "user_message_id", "source_receipt_id") @@ -336,7 +357,7 @@ def _browser_provenance_checks( return checks, provenance -def _codex_rollout_provenance_checks( +def _local_codex_rollout_structure_checks( rollout_path: Path | None, *, sessions_root: Path, @@ -348,6 +369,8 @@ def _codex_rollout_provenance_checks( artifact_hashes: dict[str, Any], messages: list[dict[str, Any]], ) -> tuple[dict[str, bool], dict[str, Any]]: + # Codex session JSONL is same-user writable. These checks establish internal + # consistency for external review, never an independently authenticated receipt. root = sessions_root.resolve() resolved = rollout_path.resolve() if rollout_path is not None else Path() contained = bool(rollout_path) and resolved.is_file() and root in resolved.parents @@ -513,9 +536,8 @@ def _codex_rollout_provenance_checks( authorization_event_at = _parse_aware_timestamp(user_event.get("timestamp")) if user_event else None capture_source = capture.get("capture_source") if isinstance(capture.get("capture_source"), dict) else {} checks = { - "codex_rollout_log_is_trusted_external_file": contained - and outside_evidence_root - and thread_id in resolved.name, + "codex_rollout_log_has_expected_local_sessions_shape": contained and thread_id in resolved.name, + "codex_rollout_log_is_separate_from_evidence_root": outside_evidence_root, "codex_rollout_log_jsonl_valid": jsonl_valid and bool(events), "codex_rollout_session_meta_matches_thread": session_meta_ids == [thread_id], "codex_rollout_has_exact_single_authorization_event": len(matching_user_events) == 1, @@ -726,7 +748,7 @@ def verify_capture( packet_path: Path, evidence_root: Path, codex_rollout_log: Path | None = None, - codex_sessions_root: Path = DEFAULT_CODEX_SESSIONS_ROOT, + codex_sessions_root: Path | None = None, ) -> dict[str, Any]: if capture is None: packet_integrity = state_collector.packet_checks(packet) @@ -740,12 +762,9 @@ def verify_capture( return { "schema": SCHEMA, "generated_at_utc": datetime.now(timezone.utc).isoformat(), - "mode": "telegram_visible_unseen_chain_capture_verifier", + "mode": "telegram_visible_unseen_chain_preparation_verifier", "status": "awaiting_action_time_authorization" if ready else "fail", - "receipt_ready": False, - "current_tier": "T0_packet_plus_T3_preflight" if ready else "T0_failed_preflight", - "required_tier": "T3_live_readonly", - "telegram_visible_messages_sent": False, + **_preparation_only_fields(preparation_ready=ready), "mutates_db": False, "packet_path": str(packet_path), "preflight_path": str(DEFAULT_PREFLIGHT), @@ -760,11 +779,12 @@ def verify_capture( }, "claim_ceiling": { "proven": ( - "The exact packet and live zero-mutation preflight are ready." + "The caller-supplied packet and preflight are structurally ready for external review." if ready else "No readiness claim; packet or preflight integrity validation failed." ), "not_proven": [ + "independently authenticated platform or browser receipt", "Telegram-visible message delivery", "Telegram-visible Leo replies", "post-send fingerprint equality", @@ -834,9 +854,9 @@ def verify_capture( messages=messages, artifact_hashes=artifact_hashes, ) - codex_rollout_checks, codex_rollout_evidence = _codex_rollout_provenance_checks( + codex_rollout_checks, codex_rollout_evidence = _local_codex_rollout_structure_checks( codex_rollout_log, - sessions_root=codex_sessions_root, + sessions_root=codex_sessions_root or DEFAULT_CODEX_SESSIONS_ROOT, evidence_root=evidence_root, packet=packet, capture=capture, @@ -971,8 +991,8 @@ def verify_capture( ), **semantics, } - outcomes = { - "telegram_visible_three_turn_chain": all( + preparation_outcomes = { + "caller_bundle_three_turn_chain_structurally_consistent": all( checks[key] for key in ( "authenticated_chrome_transport_declared", @@ -999,7 +1019,7 @@ def verify_capture( "turn_accessibility_binds_exact_messages_and_replies", ) ), - "visible_db_grounded_challenge": all( + "caller_bundle_db_grounded_challenge_structurally_consistent": all( checks[key] for key in ( "visible_db_object_selected_without_operator_id", @@ -1009,7 +1029,7 @@ def verify_capture( "independent_db_object_matches_visible_subject", ) ), - "visible_review_only_revision": all( + "caller_bundle_review_only_revision_structurally_consistent": all( checks[key] for key in ( "multiple_review_only_candidates_proposed", @@ -1019,24 +1039,23 @@ def verify_capture( "reply_claimed_no_mutation", ) ), - "canonical_state_unchanged": checks["canonical_fingerprint_unchanged_from_preflight"], + "caller_bundle_canonical_state_claim_structurally_consistent": checks[ + "canonical_fingerprint_unchanged_from_preflight" + ], } - passed = all(checks.values()) and all(outcomes.values()) + preparation_ready = all(checks.values()) and all(preparation_outcomes.values()) return { "schema": SCHEMA, "generated_at_utc": datetime.now(timezone.utc).isoformat(), - "mode": "telegram_visible_unseen_chain_capture_verifier", - "status": "pass" if passed else "fail", - "receipt_ready": passed, - "current_tier": "T3_live_readonly" if passed else "T2_or_lower_incomplete_visible_proof", - "required_tier": "T3_live_readonly", - "telegram_visible_messages_sent": passed, - "capture_claimed_messages_sent": True, + "mode": "telegram_visible_unseen_chain_preparation_verifier", + "status": PREPARATION_STATUS if preparation_ready else "fail", + **_preparation_only_fields(preparation_ready=preparation_ready), + "capture_bundle_present": True, "production_apply_executed": False, "mutates_db": False, "packet_path": str(packet_path), "checks": checks, - "outcomes": outcomes, + "preparation_outcomes": preparation_outcomes, "selected_subject": { "ref": subject_ref, "table": subject_match.get("table"), @@ -1060,13 +1079,15 @@ def verify_capture( }, "claim_ceiling": { "proven": ( - "One exact authenticated-Chrome Telegram chain visibly selected and challenged a DB object, " - "proposed and revised review-only knowledge, preserved the approval/apply boundary, and left the " - "canonical fingerprint unchanged." - if passed - else "No T3 claim; at least one visible, semantic, binding, or state check failed." + "The caller-supplied capture bundle is structurally consistent, including its chronology, evidence, " + "semantic, and unchanged-state claims. It is ready for an independently authenticated platform or " + "browser receipt outside this verifier; no live activity is authenticated here." + if preparation_ready + else "No preparation claim; at least one structural, semantic, binding, or state check failed." ), "not_proven": [ + "T3 live-readonly Telegram proof", + "Telegram-visible message delivery or replies", "canonical proposal staging or apply", "agent-to-agent review", "GCP runtime parity for the Telegram-visible chain", @@ -1086,10 +1107,12 @@ def write_markdown(path: Path, data: dict[str, Any]) -> None: "", f"Generated UTC: `{data['generated_at_utc']}`", f"Status: `{data['status']}`", + f"Preparation ready: `{data['preparation_ready']}`", f"Receipt ready: `{data['receipt_ready']}`", f"Current tier: `{data['current_tier']}`", f"Required tier: `{data['required_tier']}`", f"Telegram-visible messages sent: `{data['telegram_visible_messages_sent']}`", + f"Independent live receipt verified: `{data['live_receipt_boundary']['verified']}`", f"Mutates DB: `{data['mutates_db']}`", "", "## Checks", @@ -1102,12 +1125,17 @@ def write_markdown(path: Path, data: dict[str, Any]) -> None: "", "## Awaiting Authorized Capture", "", - "The packet and preflight are ready. No Telegram message has been sent by this verifier.", - "A future T3 receipt also requires the exact platform authorization event and Chrome-backend capture receipts from the bound Codex rollout log.", + "The packet and preflight are structurally ready. No Telegram message has been sent by this verifier.", + "A future T3 receipt requires an independently authenticated platform/browser authority outside this verifier.", ] ) lines.extend( [ + "", + "## Trust Boundary", + "", + "Local files, capture artifacts, and Codex rollout JSONL are caller-writable preparation evidence only. " + "This verifier cannot accept or mint a live receipt.", "", "## Claim Ceiling", "", @@ -1129,7 +1157,7 @@ def parse_args(argv: list[str] | None = None) -> argparse.Namespace: parser.add_argument( "--codex-rollout-log", type=Path, - help="Platform rollout JSONL containing the exact user authorization and Chrome capture tool receipts", + help="Local Codex rollout JSONL for preparation-structure checks; this never authenticates a live receipt", ) parser.add_argument("--out", type=Path, default=DEFAULT_OUT) parser.add_argument("--markdown-out", type=Path, default=DEFAULT_MARKDOWN_OUT) @@ -1165,7 +1193,7 @@ def main(argv: list[str] | None = None) -> int: sort_keys=True, ) ) - return 0 if receipt["status"] in {"pass", "awaiting_action_time_authorization"} else 2 + return 0 if receipt["status"] in {PREPARATION_STATUS, "awaiting_action_time_authorization"} else 2 if __name__ == "__main__": diff --git a/tests/test_verify_telegram_visible_unseen_chain.py b/tests/test_verify_telegram_visible_unseen_chain.py index d70dc87..0247a14 100644 --- a/tests/test_verify_telegram_visible_unseen_chain.py +++ b/tests/test_verify_telegram_visible_unseen_chain.py @@ -383,9 +383,9 @@ def verified_fixture(tmp_path: Path) -> tuple[dict, Path, dict, dict, dict, Path packet, packet_path = packet_and_path(tmp_path) before = preflight(packet, packet_path) after = postflight(packet, packet_path, before) - capture, trusted_sha256 = good_capture(packet, tmp_path) + capture, rollout = good_capture(packet, tmp_path) capture["preflight_state_token_sha256"] = before["state_token_sha256"] - return packet, packet_path, before, after, capture, trusted_sha256 + return packet, packet_path, before, after, capture, rollout def run_verifier( @@ -425,22 +425,72 @@ def test_no_capture_returns_awaiting_authorization_template(tmp_path: Path) -> N ) assert receipt["status"] == "awaiting_action_time_authorization" + assert receipt["preparation_ready"] is True + assert receipt["receipt_ready"] is False + assert receipt["current_tier"] == verifier.PREPARATION_TIER assert receipt["telegram_visible_messages_sent"] is False + assert receipt["live_receipt_boundary"]["accepted_by_this_api"] is False + assert receipt["live_receipt_boundary"]["verified"] is False assert receipt["capture_template"]["schema"] == verifier.CAPTURE_SCHEMA assert receipt["capture_template"]["messages"][0]["prompt_id"] == "OOS-CHAIN-01" -def test_good_chrome_capture_and_unchanged_fingerprint_pass_t3(tmp_path: Path) -> None: - packet, packet_path, before, after, capture, trusted = verified_fixture(tmp_path) +def test_public_verifier_keeps_fully_well_formed_all_local_forgery_preparation_only( + tmp_path: Path, + monkeypatch: pytest.MonkeyPatch, +) -> None: + _packet, packet_path, before, after, capture, rollout = verified_fixture(tmp_path) + preflight_path = tmp_path / "preflight.json" + capture_path = tmp_path / "capture.json" + postflight_path = tmp_path / "postflight.json" + out_path = tmp_path / "receipt.json" + markdown_path = tmp_path / "receipt.md" + verifier.write_json(preflight_path, before) + verifier.write_json(capture_path, capture) + verifier.write_json(postflight_path, after) + monkeypatch.setattr(verifier, "DEFAULT_CODEX_SESSIONS_ROOT", rollout.parents[3]) - receipt = run_verifier(packet, packet_path, before, after, capture, trusted, tmp_path) + exit_code = verifier.main( + [ + "--packet", + str(packet_path), + "--preflight", + str(preflight_path), + "--capture-json", + str(capture_path), + "--postflight", + str(postflight_path), + "--evidence-root", + str(tmp_path), + "--codex-rollout-log", + str(rollout), + "--out", + str(out_path), + "--markdown-out", + str(markdown_path), + ] + ) + receipt = json.loads(out_path.read_text(encoding="utf-8")) - assert receipt["status"] == "pass" - assert receipt["receipt_ready"] is True - assert receipt["current_tier"] == "T3_live_readonly" + assert exit_code == 0 + assert receipt["status"] == verifier.PREPARATION_STATUS + assert receipt["verification_scope"] == "caller_writable_preparation_structure" + assert receipt["preparation_ready"] is True + assert receipt["receipt_ready"] is False + assert receipt["current_tier"] == verifier.PREPARATION_TIER + assert receipt["telegram_visible_messages_sent"] is False + assert receipt["live_receipt_boundary"] == { + "accepted_by_this_api": False, + "authority": "independently_authenticated_platform_browser_receipt", + "local_inputs_are": "caller_writable_preparation_evidence", + "required": True, + "verified": False, + } assert all(receipt["checks"].values()) - assert all(receipt["outcomes"].values()) + assert all(receipt["preparation_outcomes"].values()) assert receipt["selected_subject"]["row_id"] == SUBJECT_ID + assert "T3_live_readonly" not in receipt["current_tier"] + assert "caller-writable preparation evidence only" in markdown_path.read_text(encoding="utf-8") def test_self_declared_browser_provenance_without_codex_rollout_cannot_pass_t3( @@ -452,7 +502,7 @@ def test_self_declared_browser_provenance_without_codex_rollout_cannot_pass_t3( assert receipt["status"] == "fail" assert receipt["telegram_visible_messages_sent"] is False - assert receipt["checks"]["codex_rollout_log_is_trusted_external_file"] is False + assert receipt["checks"]["codex_rollout_log_has_expected_local_sessions_shape"] is False assert receipt["checks"]["codex_rollout_capture_events_are_chrome_backend"] is False @@ -475,10 +525,10 @@ def test_non_chrome_rollout_capture_events_are_rejected(tmp_path: Path) -> None: def test_bot_api_capture_is_rejected(tmp_path: Path) -> None: - packet, packet_path, before, after, capture, trusted = verified_fixture(tmp_path) + packet, packet_path, before, after, capture, rollout = verified_fixture(tmp_path) capture["capture_source"]["transport"] = "telegram_bot_api" - receipt = run_verifier(packet, packet_path, before, after, capture, trusted, tmp_path) + receipt = run_verifier(packet, packet_path, before, after, capture, rollout, tmp_path) assert receipt["status"] == "fail" assert receipt["checks"]["authenticated_chrome_transport_declared"] is False @@ -486,10 +536,10 @@ def test_bot_api_capture_is_rejected(tmp_path: Path) -> None: def test_postflight_fingerprint_drift_is_rejected(tmp_path: Path) -> None: - packet, packet_path, before, after, capture, trusted = verified_fixture(tmp_path) + packet, packet_path, before, after, capture, rollout = verified_fixture(tmp_path) after["remote"]["fingerprint_after"]["fingerprint_sha256"] = "0" * 64 - receipt = run_verifier(packet, packet_path, before, after, capture, trusted, tmp_path) + receipt = run_verifier(packet, packet_path, before, after, capture, rollout, tmp_path) assert receipt["status"] == "fail" assert receipt["checks"]["postflight_state_token_derivation_valid"] is False @@ -497,10 +547,10 @@ def test_postflight_fingerprint_drift_is_rejected(tmp_path: Path) -> None: def test_message_text_drift_is_rejected(tmp_path: Path) -> None: - packet, packet_path, before, after, capture, trusted = verified_fixture(tmp_path) + packet, packet_path, before, after, capture, rollout = verified_fixture(tmp_path) capture["messages"][1]["sent_text"] += " extra" - receipt = run_verifier(packet, packet_path, before, after, capture, trusted, tmp_path) + receipt = run_verifier(packet, packet_path, before, after, capture, rollout, tmp_path) assert receipt["status"] == "fail" assert receipt["checks"]["sent_text_exact"] is False @@ -518,31 +568,31 @@ def test_sent_and_reply_message_id_reuse_is_rejected(tmp_path: Path) -> None: def test_copied_reply_not_present_in_accessibility_is_rejected(tmp_path: Path) -> None: - packet, packet_path, before, after, capture, trusted = verified_fixture(tmp_path) + packet, packet_path, before, after, capture, rollout = verified_fixture(tmp_path) capture["messages"][0]["reply"] += " copied-only suffix" - receipt = run_verifier(packet, packet_path, before, after, capture, trusted, tmp_path) + receipt = run_verifier(packet, packet_path, before, after, capture, rollout, tmp_path) assert receipt["status"] == "fail" assert receipt["checks"]["turn_accessibility_binds_exact_messages_and_replies"] is False def test_all_prompts_sent_before_replies_is_rejected(tmp_path: Path) -> None: - packet, packet_path, before, after, capture, trusted = verified_fixture(tmp_path) + packet, packet_path, before, after, capture, rollout = verified_fixture(tmp_path) capture["messages"][0]["reply_at_utc"] = "2026-07-15T00:02:30Z" - receipt = run_verifier(packet, packet_path, before, after, capture, trusted, tmp_path) + receipt = run_verifier(packet, packet_path, before, after, capture, rollout, tmp_path) assert receipt["status"] == "fail" assert receipt["checks"]["strict_send_reply_turn_order"] is False def test_after_the_fact_authorization_is_rejected(tmp_path: Path) -> None: - packet, packet_path, before, after, capture, _trusted = verified_fixture(tmp_path) + packet, packet_path, before, after, capture, _rollout = verified_fixture(tmp_path) capture["operator_authorization_captured_at_utc"] = "2026-07-15T00:01:10Z" - trusted = refresh_provenance_and_rollout(packet, capture, tmp_path) + rollout = refresh_provenance_and_rollout(packet, capture, tmp_path) - receipt = run_verifier(packet, packet_path, before, after, capture, trusted, tmp_path) + receipt = run_verifier(packet, packet_path, before, after, capture, rollout, tmp_path) assert receipt["status"] == "fail" assert receipt["checks"]["captured_authorization_before_first_send"] is False @@ -550,22 +600,22 @@ def test_after_the_fact_authorization_is_rejected(tmp_path: Path) -> None: @pytest.mark.parametrize("timestamp", ["2026-07-15T00:01:00", "not-a-timestamp"]) def test_naive_or_malformed_timestamps_are_rejected(tmp_path: Path, timestamp: str) -> None: - packet, packet_path, before, after, capture, trusted = verified_fixture(tmp_path) + packet, packet_path, before, after, capture, rollout = verified_fixture(tmp_path) capture["messages"][0]["sent_at_utc"] = timestamp - receipt = run_verifier(packet, packet_path, before, after, capture, trusted, tmp_path) + receipt = run_verifier(packet, packet_path, before, after, capture, rollout, tmp_path) assert receipt["status"] == "fail" assert receipt["checks"]["timestamps_valid_and_timezone_aware"] is False def test_reused_per_turn_evidence_is_rejected(tmp_path: Path) -> None: - packet, packet_path, before, after, capture, _trusted = verified_fixture(tmp_path) + packet, packet_path, before, after, capture, _rollout = verified_fixture(tmp_path) capture["messages"][1]["turn_screenshot"] = capture["messages"][0]["turn_screenshot"] capture["messages"][1]["turn_accessibility"] = capture["messages"][0]["turn_accessibility"] - trusted = refresh_provenance_and_rollout(packet, capture, tmp_path) + rollout = refresh_provenance_and_rollout(packet, capture, tmp_path) - receipt = run_verifier(packet, packet_path, before, after, capture, trusted, tmp_path) + receipt = run_verifier(packet, packet_path, before, after, capture, rollout, tmp_path) assert receipt["status"] == "fail" assert receipt["checks"]["per_turn_screenshot_hashes_distinct_nonempty"] is False @@ -573,56 +623,59 @@ def test_reused_per_turn_evidence_is_rejected(tmp_path: Path) -> None: def test_final_capture_may_reuse_turn_three_when_documented(tmp_path: Path) -> None: - packet, packet_path, before, after, capture, _trusted = verified_fixture(tmp_path) + packet, packet_path, before, after, capture, _rollout = verified_fixture(tmp_path) capture["capture_source"]["final_screenshot"] = capture["messages"][2]["turn_screenshot"] capture["capture_source"]["final_accessibility"] = capture["messages"][2]["turn_accessibility"] capture["capture_source"]["final_capture_reuses_turn_3"] = True capture["capture_source"]["final_capture_reuse_reason"] = ( "The final Chrome capture is the retained third-turn response state." ) - trusted = refresh_provenance_and_rollout(packet, capture, tmp_path) + rollout = refresh_provenance_and_rollout(packet, capture, tmp_path) - receipt = run_verifier(packet, packet_path, before, after, capture, trusted, tmp_path) + receipt = run_verifier(packet, packet_path, before, after, capture, rollout, tmp_path) - assert receipt["status"] == "pass" + assert receipt["status"] == verifier.PREPARATION_STATUS + assert receipt["preparation_ready"] is True + assert receipt["receipt_ready"] is False + assert receipt["telegram_visible_messages_sent"] is False assert receipt["checks"]["final_capture_reuse_policy_satisfied"] is True def test_undocumented_final_turn_three_reuse_is_rejected(tmp_path: Path) -> None: - packet, packet_path, before, after, capture, _trusted = verified_fixture(tmp_path) + packet, packet_path, before, after, capture, _rollout = verified_fixture(tmp_path) capture["capture_source"]["final_screenshot"] = capture["messages"][2]["turn_screenshot"] - trusted = refresh_provenance_and_rollout(packet, capture, tmp_path) + rollout = refresh_provenance_and_rollout(packet, capture, tmp_path) - receipt = run_verifier(packet, packet_path, before, after, capture, trusted, tmp_path) + receipt = run_verifier(packet, packet_path, before, after, capture, rollout, tmp_path) assert receipt["status"] == "fail" assert receipt["checks"]["final_capture_reuse_policy_satisfied"] is False def test_evidence_path_escape_is_rejected(tmp_path: Path) -> None: - packet, packet_path, before, after, capture, trusted = verified_fixture(tmp_path) + packet, packet_path, before, after, capture, rollout = verified_fixture(tmp_path) outside = tmp_path.parent / "outside-turn.png" write_png(outside, (1, 2, 3, 255)) capture["messages"][0]["turn_screenshot"] = str(outside) - receipt = run_verifier(packet, packet_path, before, after, capture, trusted, tmp_path) + receipt = run_verifier(packet, packet_path, before, after, capture, rollout, tmp_path) assert receipt["status"] == "fail" assert receipt["checks"]["all_evidence_paths_contained_in_root"] is False def test_non_png_screenshot_is_rejected(tmp_path: Path) -> None: - packet, packet_path, before, after, capture, _trusted = verified_fixture(tmp_path) + packet, packet_path, before, after, capture, _rollout = verified_fixture(tmp_path) Path(capture["messages"][0]["turn_screenshot"]).write_bytes(b"not a png") - trusted = refresh_provenance_and_rollout(packet, capture, tmp_path) + rollout = refresh_provenance_and_rollout(packet, capture, tmp_path) - receipt = run_verifier(packet, packet_path, before, after, capture, trusted, tmp_path) + receipt = run_verifier(packet, packet_path, before, after, capture, rollout, tmp_path) assert receipt["status"] == "fail" assert receipt["checks"]["screenshots_are_valid_png_with_metadata"] is False -def test_fabricated_local_bundle_without_supported_state_or_trusted_chrome_provenance_fails( +def test_malformed_local_bundle_without_supported_state_or_rollout_structure_fails( tmp_path: Path, ) -> None: packet, packet_path = packet_and_path(tmp_path) @@ -696,18 +749,18 @@ def test_fabricated_local_bundle_without_supported_state_or_trusted_chrome_prove assert receipt["checks"]["capture_schema_supported"] is False assert receipt["checks"]["preflight_schema_supported"] is False assert receipt["checks"]["preflight_state_token_derivation_valid"] is False - assert receipt["checks"]["codex_rollout_log_is_trusted_external_file"] is False + assert receipt["checks"]["codex_rollout_log_has_expected_local_sessions_shape"] is False assert receipt["checks"]["codex_rollout_has_exact_single_authorization_event"] is False assert receipt["checks"]["screenshots_are_valid_png_with_metadata"] is False assert receipt["checks"]["per_turn_screenshot_hashes_distinct_nonempty"] is False def test_state_token_tampering_is_rejected(tmp_path: Path) -> None: - packet, packet_path, before, after, capture, trusted = verified_fixture(tmp_path) + packet, packet_path, before, after, capture, rollout = verified_fixture(tmp_path) before = copy.deepcopy(before) before["generated_at_utc"] = "2026-07-14T23:58:00Z" - receipt = run_verifier(packet, packet_path, before, after, capture, trusted, tmp_path) + receipt = run_verifier(packet, packet_path, before, after, capture, rollout, tmp_path) assert receipt["status"] == "fail" assert receipt["checks"]["preflight_state_token_derivation_valid"] is False