"""Validate planning data only; this does not execute or accept the game.""" from pathlib import Path import argparse import collections import hashlib import json PLAN = Path(__file__).resolve().parent ROOT = PLAN.parents[2] def read(name): return json.loads((PLAN / name).read_text()) def digest(path): return hashlib.sha256(path.read_bytes()).hexdigest() def limited_view_registry_errors(atomic, declaration): """Validate declared view payloads against an immutable prior register.""" errors = [] def require(ok, message): if not ok: raise ValueError(message) try: ref = declaration["manifest"] path = (PLAN / ref["path"]).resolve() require(digest(path) == ref["sha256"], "limited view manifest SHA") patch = json.loads(path.read_text()) require(type(patch["schema_version"]) is int and patch["schema_version"] == 1 and type(patch["whole_atom_status_changes"]) is int and patch["whole_atom_status_changes"] == 0, "limited view manifest scope") baseline_ref = patch["baseline_registry"] baseline_path = (PLAN / baseline_ref["path"]).resolve() require(digest(baseline_path) == baseline_ref["sha256"], "limited view baseline SHA") baseline = json.loads(baseline_path.read_text()) expected = json.loads(json.dumps(baseline)) by_id = {row["id"]: row for row in expected["requirements"]} matrix = patch["view_results_patch"] require(type(matrix) is dict and bool(matrix), "limited view nonempty ID matrix") require(set(matrix) <= set(by_id), "limited view unknown requirement ID") allowed_views = set(baseline["completion_views"]) allowed_states = set(read("progress_contract.json")["view_states"]) declared_counts = collections.Counter() reference_pins = patch["reference_pins"] for rid, views in matrix.items(): require(type(views) is dict and bool(views) and set(views) <= allowed_views, "limited view empty/unknown view: " + rid) for view, result in views.items(): require(type(result) is dict and result.get("state") in allowed_states and result.get("state") != "unverified", "limited view state: " + rid) require(type(result.get("evidence_refs")) is list and bool(result["evidence_refs"]) and bool(result.get("reviewer")), "limited view missing evidence/reviewer: " + rid) if result["state"] == "not_applicable": require(bool(result.get("not_applicable_reason")) and bool(result.get("source_or_explicit_user_decision")), "limited view unsupported not-applicable: " + rid) declared_counts[result["state"]] += 1 for evidence in result["evidence_refs"] + [result["current_adoption_evidence"]]: require(type(evidence) is str, "limited view reference type: " + rid) filename, separator, fragment = evidence.partition("#") require(separator == "#" and bool(fragment) and evidence in reference_pins, "limited view resolved reference: " + rid) evidence_path = (PLAN / filename).resolve() require(digest(evidence_path) == reference_pins[evidence], "limited view evidence SHA: " + rid) selected = json.loads(evidence_path.read_text()) for key in fragment.split("/"): selected = selected[key] require(bool(selected), "limited view empty referenced fragment: " + rid) by_id[rid]["view_results"][view] = result for key in ["atom_count", "view_count"]: require(type(declaration[key]) is int and type(patch[key]) is int, "limited view count type: " + key) require(len(matrix) == declaration["atom_count"] == patch["atom_count"], "limited view atom count") require(sum(declared_counts.values()) == declaration["view_count"] == patch["view_count"], "limited view observation count") require(type(declaration["state_counts"]) is dict and type(patch["state_counts"]) is dict and all(type(value) is int for value in declaration["state_counts"].values()) and dict(declared_counts) == declaration["state_counts"] == patch["state_counts"], "limited view state counts") require(json.dumps(atomic, ensure_ascii=False, sort_keys=True, separators=(",", ":"), allow_nan=False) == json.dumps(expected, ensure_ascii=False, sort_keys=True, separators=(",", ":"), allow_nan=False), "limited view type-exact payload / untouched registry mismatch") for row in atomic["requirements"]: require(row["implementation_state"] == "not_reaudited" and row["acceptance_state"] == row["status"] == "unverified", "limited evidence changed whole-atom status: " + row["id"]) except (OSError, ValueError, KeyError, TypeError, AttributeError) as error: errors.append(type(error).__name__ + ": " + str(error)) return errors def main(): parser = argparse.ArgumentParser(description=__doc__) parser.add_argument("--initial-snapshot", action="store_true", help="Also verify the immutable initial planning state") parser.add_argument("--verify-baseline", action="store_true", help="Also compare current source bytes to the historical baseline") args = parser.parse_args() packages = read("execution/work_packages.initial.json" if args.initial_snapshot else "work_packages.json") coverage = read("requirement_coverage.json") baseline = read("baseline.json") decisions = read("decisions.json") contract = read("execution/progress_contract.initial.json" if args.initial_snapshot else "progress_contract.json") checks = [] def check(name, condition): checks.append({"name": name, "passed": bool(condition)}) if args.initial_snapshot: initial = read("execution/PLANNING_DATA_INITIAL_SNAPSHOT.json") check("immutable_initial_planning_data_pins", all( (PLAN / name).is_file() and digest(PLAN / name) == value for name, value in initial["sha256"].items() )) ids = [row["id"] for row in packages] expected = {f"P{i:02d}" for i in range(30)} check("all30_unique_package_ids", len(ids) == 30 and set(ids) == expected) tasks = [task for row in packages for task in row["remaining_deliverables"]] task_ids = {task["id"] for task in tasks} check("unique_delivery_ids", len(tasks) == len(task_ids) and all(p["remaining_deliverables"] for p in packages)) if args.initial_snapshot: check("initial88_delivery_ids", len(tasks) == 88) check("delivery_scope_and_acceptance", all(t["work"] and t["acceptance"] for t in tasks)) states = {"planned", "in_progress", "blocked", "completed"} check("valid_delivery_states", all(t["state"] in states for t in tasks)) check("completed_delivery_requires_evidence", all(t["state"] != "completed" or t["evidence"] for t in tasks)) check("linked_delivery_evidence_exists", all( isinstance(ref, dict) and (ROOT / ref["path"]).is_file() for task in tasks for ref in task["evidence"] )) if args.initial_snapshot: check("initial_remaining_delivery_not_claimed_done", all(t["state"] == "planned" and not t["evidence"] for t in tasks)) check("known_dependency_ids", all(set(row["depends_on"]) <= expected for row in packages)) by_id = {row["id"]: row for row in packages} visited, active = set(), set() def acyclic(node): if node in active: return False if node in visited: return True active.add(node) if not all(acyclic(dep) for dep in by_id[node]["depends_on"] if dep in by_id): return False active.remove(node) visited.add(node) return True check("dependency_graph_acyclic", all(acyclic(node) for node in ids)) old_requirements = json.loads((ROOT / "docs/traceability/original/requirements.json").read_text()) original_ids = {r["id"] for r in old_requirements} mapped_ids = [r["requirement_id"] for r in coverage] check("all75_original_groups_once", len(mapped_ids) == 75 and set(mapped_ids) == original_ids) check("feature71_schedule4", sum(r["scope"] == "feature_or_content" for r in coverage) == 71 and sum(r["scope"] == "schedule" for r in coverage) == 4) check("coverage_known_packages", all(set(r["work_packages"]) <= expected for r in coverage)) check("coverage_known_delivery_ids", all(set(r["remaining_deliverable_ids"]) <= task_ids for r in coverage)) check("coverage_exact_package_deliveries", all(set(r["remaining_deliverable_ids"]) == {d["id"] for p in packages if p["id"] in r["work_packages"] for d in p["remaining_deliverables"]} for r in coverage)) check("package_and_requirement_mapping_agree", all({p["id"] for p in packages if r["requirement_id"] in p["requirement_ids"]} == set(r["work_packages"]) for r in coverage)) check("source_lines_preserved", all(r["source_lines"] == next(x["source_lines"] for x in old_requirements if x["id"] == r["requirement_id"]) for r in coverage)) check("old_status_not_promoted", all("current_status" not in r and r["current_atomic_acceptance"] == "not_reaudited" for r in coverage)) supplements = {s for p in packages for s in p["supplement_ids"]} check("all10_facility_supplements", supplements == {f"F-{i:02d}" for i in range(1, 11)}) check("P09_owns10_supplements", set(by_id["P09"]["supplement_ids"]) == supplements) pending = {d["id"] for d in decisions["pending"]} check("all10_pending_decision_groups", pending == {f"D{i:02d}" for i in range(1, 11)}) check("known_decision_references", all(set(p["decisions"]) <= pending for p in packages)) check("all14_confirmed_decisions", {d["id"] for d in decisions["confirmed"]} == {f"A{i:02d}" for i in range(1, 15)}) check("confirmed_decision_references_exist", all((PLAN / d["reference"]).is_file() for d in decisions["confirmed"] if "reference" in d)) state_counts = dict(collections.Counter(p["state"] for p in packages)) check("valid_package_states", all(p["state"] in states for p in packages)) check("new_completed_packages_require_evidence", all(p["state"] != "completed" or p["legacy_state"] == "completed" or p.get("completion_evidence") for p in packages)) check("acceptance_conditions_not_claimed_results", all("cross_cutting_done" not in p and p["cross_cutting_acceptance_scope"] for p in packages)) check("initial_revision_history_preserved", dict(collections.Counter(p["initial_revision_state"] for p in packages)) == baseline["revised_package_state_counts"]) if args.initial_snapshot: check("initial_revised_state_counts", state_counts == baseline["revised_package_state_counts"] == {"completed": 1, "in_progress": 25, "planned": 4}) check("initial_no_new_completed_packages", all(p["state"] != "completed" or p["legacy_state"] == "completed" for p in packages)) check("initial_eight_partial_state_promotions", {p["id"] for p in packages if p["state"] != p["legacy_state"]} == {"P09", "P14", "P15", "P16", "P20", "P23", "P25", "P28"}) check("initial_atomic_denominator_not_invented", baseline["atomic_denominator"] is None and baseline["overall_atomic_implementation_percent"] is None and baseline["overall_atomic_acceptance_percent"] is None) check("progress_contract8_views", len(contract["completion_views"]) == 8) check("progress_no_partial_credit", contract["partial_credit"] is False) known_denominator = None final_denominator = None if contract["denominator_frozen"]: check("frozen_denominator_has_register", bool(contract["atomic_register"]) and (PLAN / contract["atomic_register"]).is_file()) atomic = read(contract["atomic_register"]) freeze = read(contract["atomic_denominator_freeze"]) index = read(contract["current_evidence_index"]) known_denominator = len(atomic["denominator_ids"]) final_denominator = contract["final_atomic_denominator"] check("known_denominator_matches_frozen_register", contract["known_condition_denominator"] == freeze["denominator"] == known_denominator and freeze["denominator_ids"] == atomic["denominator_ids"]) check("progress_register_pin_matches", contract["atomic_register_sha256_at_integration"] == digest(PLAN / contract["atomic_register"])) check("evidence_index_register_pin_matches", index["atomic_register_sha256"] == digest(PLAN / contract["atomic_register"]) and index["known_condition_denominator"] == known_denominator) check("progress_index_pin_matches", contract["current_evidence_index_sha256_at_integration"] == digest(PLAN / contract["current_evidence_index"])) check("known_counts_match_freeze", contract["current_whole_atom_implementation_count"] == len(freeze["implemented_ids"]) and contract["current_whole_atom_acceptance_count"] == len(freeze["accepted_ids"])) check("unresolved_final_denominator_not_reported_as_total", contract["final_denominator_established"] or ( final_denominator is None and all(contract[key] is None for key in [ "overall_atomic_implementation_percent", "overall_atomic_acceptance_percent", "total_game_implementation_percent", "total_game_acceptance_percent" ]) and atomic["final_denominator_established"] is False and freeze["final_denominator_established"] is False )) check("static_leads_not_whole_atom_acceptance", index["whole_atom_acceptance_claimed"] is False and index["complete_runtime_ui_save_review"] is False) if contract["atomic_implementation_state"] == "not_reaudited": if contract.get("limited_view_review_manifest"): check("declared_limited_views_whole_atoms_unreviewed", not limited_view_registry_errors( atomic, contract["limited_view_review_manifest"] ) and index.get("limited_view_review_manifest") == contract["limited_view_review_manifest"]) else: check("unreviewed_atomic_views_remain_unverified", all( view["state"] == "unverified" and view["implementation_state"] == "not_reaudited" for row in atomic["requirements"] for view in row["view_results"].values() )) snapshot = read(contract["progress_snapshot"]) regression = snapshot["latest_regression_at_evidence_time"] check("regression_evidence_pin_matches", digest(ROOT / regression["path"]) == regression["sha256"] and digest(ROOT / regression["source_map_path"]) == regression["source_map_sha256"]) check("regression_source_time_scope_preserved", regression["future_source_changes_auto_accepted"] is False and regression["original_full_acceptance"] is False and regression["windows_acceptance"] is False) check("P01_P03_not_whole_package_completed", by_id["P01"]["state"] != "completed" and by_id["P03"]["state"] != "completed") else: check("unfrozen_denominator_not_assigned", contract["atomic_register"] is None) check("progress_schedule_excluded", contract["excluded_from_function_denominator"] == ["B-14.1", "B-14.2", "B-14.3", "B-14.4"]) check("baseline_materials_exist", all((ROOT / path).is_file() for path in baseline["source_pins"])) pins = baseline["facility_audit_current_pins_verified"] if args.verify_baseline: check("plan_source_pins_unchanged", all((ROOT / path).is_file() and digest(ROOT / path) == value for path, value in baseline["source_pins"].items())) check("current_facility40_pins_unchanged", len(pins) == 40 and all(digest(ROOT / path) == value for path, value in pins.items())) accepted = json.loads((ROOT / "artifacts/facility-need-pricing-production-scale-adoption-2026-10-01-r01/after.json").read_text()) if args.verify_baseline: check("accepted1396_files_unchanged", len(accepted) == 1396 and all((ROOT / path).is_file() and digest(ROOT / path) == value for path, value in accepted.items())) receipt = json.loads((ROOT / "artifacts/facility-need-pricing-production-scale-adoption-2026-10-01-r01/receipt.json").read_text()) check("retained_regression155_12310", baseline["full_regression"]["suites"] == receipt["accepted_proof"]["actual_full_suites"] == 155 and baseline["full_regression"]["checks"] == receipt["accepted_proof"]["actual_full_checks"] == 12310) check("new_game_tests_not_claimed", baseline["full_regression"]["new_engine_runs_in_plan_creation"] == 0) text = (PLAN / ("execution/IMPLEMENTATION_PLAN.initial.md" if args.initial_snapshot else "IMPLEMENTATION_PLAN.md")).read_text() check("all_package_headings", all(f"### {identifier} " in text for identifier in ids)) check("all_group_rows", all(f"| {identifier} |" in text for identifier in original_ids)) check("all_delivery_ids_in_document", all(identifier in text for identifier in task_ids)) check("encyclopedia_and_hero_rival_scope", "図鑑の完成" in text and "ライバルは別集合" in text) check("current_native_and_longplay_not_claimed", baseline["current_head_windows_native_verified"] is False and baseline["long_play_acceptance_verified"] is False) failures = [c["name"] for c in checks if not c["passed"]] result = { "plan_date_jst": baseline["plan_date_jst"], "scope": "planning consistency and static baseline reconciliation; not game acceptance", "passed": not failures, "checks": checks, "failed_checks": failures, "packages": len(packages), "remaining_delivery_units": len(tasks), "current_package_state_counts": state_counts, "initial_snapshot_checked": args.initial_snapshot, "historical_source_bytes_compared": args.verify_baseline, "covered_original_groups": len(mapped_ids), "missing_original_group_ids": sorted(original_ids - set(mapped_ids)), "facility_supplements": len(supplements), "atomic_denominator": final_denominator, "known_condition_denominator": known_denominator, "final_denominator_established": contract.get("final_denominator_established", False), "total_game_implementation_percent": None, "total_game_acceptance_percent": None, "new_game_execution_count": 0, "document_sha256": {p.name: digest(p) for p in sorted(PLAN.iterdir()) if p.is_file() and p.name not in ["plan_validation.json", "plan_validation.initial.json"]}, } output = "plan_validation.initial.json" if args.initial_snapshot else "plan_validation.json" (PLAN / output).write_text(json.dumps(result, ensure_ascii=False, indent=2) + "\n") print(json.dumps({k: v for k, v in result.items() if k not in ["checks", "document_sha256"]}, ensure_ascii=False)) if failures: raise SystemExit(1) if __name__ == "__main__": main()