Spaces:
Sleeping
Sleeping
| import importlib.util | |
| import json | |
| from pathlib import Path | |
| SCRIPT_PATH = Path(__file__).resolve().parents[1] / "scripts" / "final_launch_plan.py" | |
| SPEC = importlib.util.spec_from_file_location("final_launch_plan", SCRIPT_PATH) | |
| final_launch_plan = importlib.util.module_from_spec(SPEC) | |
| assert SPEC.loader is not None | |
| SPEC.loader.exec_module(final_launch_plan) | |
| 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, **overrides: str) -> None: | |
| statuses = { | |
| "T020": "doing", | |
| "T021": "doing", | |
| "T040": "done", | |
| "T041": "todo", | |
| "T041A": "todo", | |
| "T042": "todo", | |
| } | |
| statuses.update(overrides) | |
| write_json( | |
| root, | |
| "tasks.json", | |
| { | |
| "tasks": [ | |
| {"id": task_id, "title": task_id, "status": status} | |
| for task_id, status in statuses.items() | |
| ] | |
| }, | |
| ) | |
| def write_base_reports(root: Path) -> None: | |
| write_tasks(root) | |
| write_json( | |
| root, | |
| "docs/assets/live-credential-handoff.json", | |
| { | |
| "schema": "proofframe.live_credential_handoff.v1", | |
| "ok": False, | |
| "mode": "missing_live_env", | |
| "missing_ids": ["b2_key_id", "b2_application_key", "genblaze_api_key"], | |
| }, | |
| ) | |
| write_json( | |
| root, | |
| "docs/assets/final-operator-brief.json", | |
| { | |
| "schema": "proofframe.final_operator_brief.v1", | |
| "ready_for_secret_entry": True, | |
| "mode": "credential_entry_ready", | |
| "safe_to_submit": False, | |
| }, | |
| ) | |
| write_json( | |
| root, | |
| "docs/assets/b2-key-scope-checklist.json", | |
| { | |
| "schema": "proofframe.b2_key_scope_checklist.v1", | |
| "pre_key_creation_confirmation": { | |
| "status": "required_before_key_creation", | |
| "required_phrase": ( | |
| "I confirm ProofFrame B2 key scope: standard key, bucket proofframe-demo-a6b4e49, " | |
| "prefix campaigns/, no all-bucket access, no delete/admin permissions, " | |
| "and no secrets in chat/docs/git." | |
| ), | |
| "safe_to_store": True, | |
| }, | |
| }, | |
| ) | |
| write_json( | |
| root, | |
| "docs/assets/final-submission-control.json", | |
| { | |
| "schema": "proofframe.final_submission_control.v1", | |
| "mode": "pre_live_control", | |
| "safe_to_submit": False, | |
| "blocking_items": [ | |
| {"id": "b2_live_proof"}, | |
| {"id": "genblaze_live_proof"}, | |
| {"id": "credential_handoff"}, | |
| {"id": "public_video"}, | |
| {"id": "final_recording"}, | |
| {"id": "final_secret_scan"}, | |
| {"id": "final_submission_audit"}, | |
| {"id": "devpost_submitted"}, | |
| ], | |
| }, | |
| ) | |
| write_json( | |
| root, | |
| "docs/assets/recording-assets.json", | |
| {"schema": "proofframe.recording_assets.v1", "final_video_ready": False}, | |
| ) | |
| write_json( | |
| root, | |
| "docs/assets/submission-audit-report.json", | |
| {"schema": "proofframe.submission_audit.v1", "ok": False}, | |
| ) | |
| write_json( | |
| root, | |
| "docs/assets/devpost-submission-receipt.json", | |
| {"schema": "proofframe.devpost_submission_receipt.v1", "ok": False}, | |
| ) | |
| def test_launch_plan_is_ready_for_credential_entry(tmp_path): | |
| write_base_reports(tmp_path) | |
| plan = final_launch_plan.build_report(tmp_path) | |
| assert plan["ok"] is False | |
| assert plan["mode"] == "ready_for_credential_entry" | |
| assert plan["current_phase"] == "credential_entry" | |
| assert plan["summary"] == {"total": 6, "done": 0, "ready": 1, "blocked": 5} | |
| assert "final_env_wizard.py" in plan["next_command"] | |
| assert "I confirm ProofFrame B2 key scope" in " ".join(plan["phases"][0]["expected_artifacts"]) | |
| assert "T020" in plan["phases"][1]["task_updates_after_success"][0] | |
| assert plan["safety_policy"]["source_env_files"] is False | |
| assert "source .env.final.local" not in json.dumps(plan) | |
| def test_launch_plan_blocks_unexpected_credential_setup_gap(tmp_path): | |
| write_base_reports(tmp_path) | |
| handoff = json.loads((tmp_path / "docs/assets/live-credential-handoff.json").read_text()) | |
| handoff["missing_ids"] = ["b2_endpoint", "b2_key_id"] | |
| write_json(tmp_path, "docs/assets/live-credential-handoff.json", handoff) | |
| plan = final_launch_plan.build_report(tmp_path) | |
| assert plan["mode"] == "blocked_at_credential_entry" | |
| assert plan["phases"][0]["status"] == "blocked" | |
| assert "unexpected setup values" in plan["phases"][0]["detail"] | |
| def test_launch_plan_marks_devpost_ready_when_only_submission_remains(tmp_path): | |
| write_base_reports(tmp_path) | |
| write_tasks(tmp_path, T020="done", T021="done", T041="done", T041A="done") | |
| write_json( | |
| tmp_path, | |
| "docs/assets/live-credential-handoff.json", | |
| {"schema": "proofframe.live_credential_handoff.v1", "ok": True, "missing_ids": []}, | |
| ) | |
| write_json( | |
| tmp_path, | |
| "docs/assets/b2-live-proof-evidence.json", | |
| {"ok": True, "mode": "b2_live_verified"}, | |
| ) | |
| write_json( | |
| tmp_path, | |
| "docs/assets/final-live-proof-evidence.json", | |
| {"ok": True, "mode": "final_live_verified"}, | |
| ) | |
| write_json( | |
| tmp_path, | |
| "docs/assets/recording-assets.json", | |
| {"schema": "proofframe.recording_assets.v1", "final_video_ready": True}, | |
| ) | |
| write_json( | |
| tmp_path, | |
| "docs/assets/submission-audit-report.json", | |
| {"schema": "proofframe.submission_audit.v1", "ok": True}, | |
| ) | |
| write_json( | |
| tmp_path, | |
| "docs/assets/final-submission-control.json", | |
| { | |
| "schema": "proofframe.final_submission_control.v1", | |
| "mode": "pre_live_control", | |
| "safe_to_submit": False, | |
| "blocking_items": [{"id": "devpost_submitted"}], | |
| }, | |
| ) | |
| plan = final_launch_plan.build_report(tmp_path) | |
| assert plan["mode"] == "ready_for_devpost_submit" | |
| assert plan["current_phase"] == "devpost_submit" | |
| assert plan["summary"] == {"total": 6, "done": 5, "ready": 1, "blocked": 0} | |
| assert plan["phases"][-1]["status"] == "ready" | |
| assert "devpost_submission_receipt.py" in plan["next_command"] | |
| assert "T042" in plan["phases"][-1]["task_updates_after_success"][0] | |
| def test_launch_plan_writes_outputs(tmp_path): | |
| write_base_reports(tmp_path) | |
| plan = final_launch_plan.build_report(tmp_path) | |
| json_path = tmp_path / "out" / "launch.json" | |
| markdown_path = tmp_path / "out" / "launch.md" | |
| final_launch_plan.write_outputs(plan, json_path, markdown_path) | |
| saved = json.loads(json_path.read_text(encoding="utf-8")) | |
| markdown = markdown_path.read_text(encoding="utf-8") | |
| assert saved["schema"] == final_launch_plan.SCHEMA | |
| assert "# ProofFrame Final Launch Plan" in markdown | |
| assert "I confirm ProofFrame B2 key scope" in markdown | |
| assert "Task ledger updates after success" in markdown | |
| assert "Do not source `.env.final.local`" in markdown | |