import importlib.util import json from pathlib import Path SCRIPT_PATH = Path(__file__).resolve().parents[1] / "scripts" / "final_closeout_status.py" SPEC = importlib.util.spec_from_file_location("final_closeout_status", SCRIPT_PATH) final_closeout_status = importlib.util.module_from_spec(SPEC) assert SPEC.loader is not None SPEC.loader.exec_module(final_closeout_status) LIVE_ENV_SCRIPT_PATH = Path(__file__).resolve().parents[1] / "scripts" / "live_env_handoff.py" LIVE_ENV_SPEC = importlib.util.spec_from_file_location("live_env_handoff", LIVE_ENV_SCRIPT_PATH) live_env_handoff = importlib.util.module_from_spec(LIVE_ENV_SPEC) assert LIVE_ENV_SPEC.loader is not None LIVE_ENV_SPEC.loader.exec_module(live_env_handoff) def write_json(root: Path, relative_path: str, payload: dict) -> None: path = root / relative_path path.parent.mkdir(parents=True, exist_ok=True) path.write_text(json.dumps(payload), encoding="utf-8") def write_tasks(root: Path, *, final_ready: bool = False) -> None: statuses = { "T020": "done" if final_ready else "doing", "T021": "done" if final_ready else "doing", "T041": "done" if final_ready else "todo", "T041A": "done" if final_ready else "todo", "T042": "done" if final_ready else "todo", } write_json( root, "tasks.json", {"tasks": [{"id": task_id, "status": status} for task_id, status in statuses.items()]}, ) def write_common_reports(root: Path, *, final_ready: bool = False) -> None: write_tasks(root, final_ready=final_ready) write_json( root, "docs/assets/final-submission-control.json", { "schema": "proofframe.final_submission_control.v1", "ok": True, "control_health_ok": True, "mode": "final_submit_ready" if final_ready else "pre_live_control", "safe_to_submit": final_ready, }, ) env_file = root / ".env.test" env_file.write_text( "\n".join( [ "PROOFFRAME_STORAGE_BACKEND=b2" if final_ready else "PROOFFRAME_STORAGE_BACKEND=local", "PROOFFRAME_GENERATION_BACKEND=genblaze" if final_ready else "PROOFFRAME_GENERATION_BACKEND=mock", "B2_ENDPOINT_URL=https://s3.us-west-004.backblazeb2.com" if final_ready else "", "B2_BUCKET=proofframe-test" if final_ready else "", "B2_KEY_ID=fixture" if final_ready else "", "B2_APPLICATION_KEY=fixture" if final_ready else "", "GENBLAZE_PROVIDER=local" if final_ready else "", "GENBLAZE_API_KEY=fixture" if final_ready else "", "GENBLAZE_IMAGE_MODEL=test-image-model" if final_ready else "", ] ), encoding="utf-8", ) write_json( root, "docs/assets/live-credential-handoff.json", live_env_handoff.build_report(env_file), ) write_json( root, "docs/assets/public-video-check.json", { "schema": "proofframe.public_video_check.v1", "mode": "public_video_verified" if final_ready else "pending_video_url", "ok": final_ready, "safe_to_submit": final_ready, }, ) write_json( root, "docs/assets/final-video-publish-kit.json", { "schema": "proofframe.final_video_publish_kit.v1", "ok": True, "mode": "public_video_ready" if final_ready else "ready_for_final_upload", "safe_to_submit": final_ready, "final_video_ready": final_ready, }, ) write_json( root, "docs/assets/devpost-submission-checklist.json", { "schema": "proofframe.devpost_submission_checklist.v1", "ok": final_ready, "mode": "ready_to_submit_devpost" if final_ready else "pre_submit_blocked", "safe_to_submit": final_ready, }, ) write_json( root, "docs/assets/devpost-submission-preview.json", { "schema": "proofframe.devpost_submission_preview.v1", "ok": True, "mode": "final_preview_ready" if final_ready else "pre_live_preview_ready", "safe_to_share": True, "safe_to_submit": final_ready, }, ) write_json( root, "docs/assets/devpost-submission-receipt.json", { "schema": "proofframe.devpost_submission_receipt.v1", "ok": final_ready, "mode": "submitted" if final_ready else "pending_submission", "project_url": "https://devpost.com/software/proofframe" if final_ready else None, }, ) write_json( root, "docs/assets/secret-scan-report.json", {"schema": "proofframe.secret_scan.v1", "ok": True, "mode": "clear"}, ) write_json( root, "docs/assets/submission-audit-report.json", { "schema": "proofframe.submission_audit.v1", "ok": final_ready, "mode": "final_audit_ready" if final_ready else "pre_submit_audit_blocked", }, ) write_json( root, "docs/assets/submission-bundle-manifest.json", { "schema": "proofframe.submission_bundle.v1", "safe_to_share": True, "safe_to_submit": False, "submission_gate": {"ok": final_ready, "mode": "final_ready" if final_ready else "pre_live_safe"}, "missing_artifacts": [], }, ) write_json( root, "docs/assets/public-space-sync-report.json", {"schema": "proofframe.public_space_sync.v1", "ok": True, "mode": "public_space_synced"}, ) if final_ready: write_json( root, "docs/assets/b2-live-proof-evidence.json", {"schema": "proofframe.b2_live_proof.v1", "ok": True, "mode": "b2_live_proof_ready"}, ) write_json( root, "docs/assets/final-live-proof-evidence.json", {"schema": "proofframe.final_live_proof.v1", "ok": True, "mode": "final_live_proof_ready"}, ) def test_closeout_status_waits_for_credentials_in_pre_live_state(tmp_path): write_common_reports(tmp_path, final_ready=False) report = final_closeout_status.build_report(root=tmp_path) assert report["schema"] == "proofframe.final_closeout_status.v1" assert report["ok"] is True assert report["closeout_health_ok"] is True assert report["safe_to_submit"] is False assert report["mode"] == "waiting_for_credentials" assert report["phase"] == "credential_entry" assert ".env.final.local" in report["next_command"] gates = {gate["id"]: gate for gate in report["gates"]} assert "missing ids: storage_backend_mode, generation_backend_mode" in gates["credential_handoff"]["detail"] def test_closeout_status_can_be_final_ready(tmp_path): write_common_reports(tmp_path, final_ready=True) report = final_closeout_status.build_report(root=tmp_path) assert report["ok"] is True assert report["safe_to_submit"] is True assert report["mode"] == "final_closeout_ready" assert all(gate["ok"] for gate in report["gates"]) credential_report = report["reports"]["credential_handoff"] raw_credential_report = json.loads( (tmp_path / "docs/assets/live-credential-handoff.json").read_text(encoding="utf-8") ) assert credential_report["mode"] == "live_env_ready" assert credential_report["ready_for_live_proof"] is None assert "ready_for_live_proof" not in raw_credential_report def test_closeout_status_requires_live_tasks_done_even_when_evidence_exists(tmp_path): write_common_reports(tmp_path, final_ready=True) write_tasks(tmp_path, final_ready=False) report = final_closeout_status.build_report(root=tmp_path) assert report["safe_to_submit"] is False gates = {gate["id"]: gate for gate in report["gates"]} assert gates["b2_live_proof"]["ok"] is False assert gates["genblaze_live_proof"]["ok"] is False assert "T020 is doing" in gates["b2_live_proof"]["detail"] assert "T021 is doing" in gates["genblaze_live_proof"]["detail"] def test_closeout_status_accepts_legacy_b2_live_proof_and_waits_for_genblaze(tmp_path): write_common_reports(tmp_path, final_ready=True) write_json( tmp_path, "tasks.json", { "tasks": [ {"id": "T020", "status": "done"}, {"id": "T021", "status": "blocked"}, {"id": "T041", "status": "todo"}, {"id": "T041A", "status": "todo"}, {"id": "T042", "status": "todo"}, ] }, ) write_json( tmp_path, "docs/assets/b2-live-proof-evidence.json", { "ok": True, "storage_backend": "b2", "generation_backend": "mock", "asset_storage_backend": "b2", "manifest_storage_backend": "b2", "asset_storage_key": "campaigns/example/media/example.svg", "manifest_key": "campaigns/example/manifests/example.json", "asset_sha256": "a" * 64, "manifest_sha256": "b" * 64, }, ) (tmp_path / "docs/assets/final-live-proof-evidence.json").unlink() report = final_closeout_status.build_report(root=tmp_path) gates = {gate["id"]: gate for gate in report["gates"]} assert gates["b2_live_proof"]["ok"] is True assert gates["genblaze_live_proof"]["ok"] is False assert report["phase"] == "genblaze_live_proof" assert "run_final_live_proof.py" in report["next_command"] def test_closeout_status_accepts_legacy_final_live_proof_and_waits_for_video(tmp_path): write_common_reports(tmp_path, final_ready=True) write_json( tmp_path, "tasks.json", { "tasks": [ {"id": "T020", "status": "done"}, {"id": "T021", "status": "done"}, {"id": "T041", "status": "todo"}, {"id": "T041A", "status": "todo"}, {"id": "T042", "status": "todo"}, ] }, ) write_json( tmp_path, "docs/assets/final-live-proof-evidence.json", { "ok": True, "storage_backend": "b2", "generation_backend": "genblaze", "asset_storage_backend": "b2", "manifest_storage_backend": "b2", "asset_storage_key": "campaigns/example/media/example.svg", "manifest_key": "campaigns/example/manifests/example.json", "asset_sha256": "a" * 64, "manifest_sha256": "b" * 64, }, ) write_json( tmp_path, "docs/assets/public-video-check.json", { "schema": "proofframe.public_video_check.v1", "mode": "pending_video_url", "ok": False, "safe_to_submit": False, }, ) write_json( tmp_path, "docs/assets/final-video-publish-kit.json", { "schema": "proofframe.final_video_publish_kit.v1", "ok": True, "mode": "ready_for_final_upload", "safe_to_submit": False, "final_video_ready": False, }, ) report = final_closeout_status.build_report(root=tmp_path) gates = {gate["id"]: gate for gate in report["gates"]} assert gates["genblaze_live_proof"]["ok"] is True assert gates["public_video"]["ok"] is False assert report["phase"] == "public_video" def test_closeout_status_uses_bundle_inputs_not_bundle_safe_to_submit(tmp_path): write_common_reports(tmp_path, final_ready=True) report = final_closeout_status.build_report(root=tmp_path) gates = {gate["id"]: gate for gate in report["gates"]} assert gates["final_bundle"]["ok"] is True assert report["safe_to_submit"] is True def test_closeout_status_reports_missing_control_reports(tmp_path): write_common_reports(tmp_path, final_ready=False) (tmp_path / "docs/assets/public-space-sync-report.json").unlink() report = final_closeout_status.build_report(root=tmp_path) assert report["ok"] is False assert report["mode"] == "closeout_needs_repair" assert report["unexpected_findings"] assert "public_space_sync" in report["unexpected_findings"][0]["detail"]