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