Preserve production code, regression fixtures, audio assets and provenance, test infrastructure, and the original-completion plan and progress ledger. Final game and Windows acceptance remain pending; excluded local artifacts and native experiments are not part of this snapshot.
82 lines
3.9 KiB
Python
82 lines
3.9 KiB
Python
"""Exercise plan-validator rejection guards in temporary planning copies only."""
|
|
from contextlib import redirect_stdout
|
|
from datetime import datetime
|
|
import importlib.util
|
|
import io
|
|
import json
|
|
from pathlib import Path
|
|
import shutil
|
|
import tempfile
|
|
from zoneinfo import ZoneInfo
|
|
|
|
PLAN = Path(__file__).resolve().parents[1]
|
|
ROOT = PLAN.parents[2]
|
|
INPUTS = [
|
|
"work_packages.json", "requirement_coverage.json", "baseline.json", "decisions.json",
|
|
"progress_contract.json", "atomic_requirements.json", "atomic_denominator_freeze.json",
|
|
"current_evidence_links.json", "progress_snapshot.json", "IMPLEMENTATION_PLAN.md",
|
|
]
|
|
|
|
|
|
def exercise(case, filename, mutate, expected):
|
|
with tempfile.TemporaryDirectory(prefix="thetree-progress-guard-") as directory:
|
|
stage = Path(directory) / "docs/plans/original-completion-2026-10-02"
|
|
stage.mkdir(parents=True)
|
|
for name in INPUTS:
|
|
shutil.copyfile(PLAN / name, stage / name)
|
|
decisions = json.loads((PLAN / "decisions.json").read_text())
|
|
for decision in decisions["confirmed"]:
|
|
if "reference" in decision:
|
|
destination = stage / decision["reference"]
|
|
destination.parent.mkdir(parents=True, exist_ok=True)
|
|
shutil.copyfile(PLAN / decision["reference"], destination)
|
|
data = json.loads((stage / filename).read_text())
|
|
mutate(data)
|
|
(stage / filename).write_text(json.dumps(data, ensure_ascii=False, indent=2) + "\n")
|
|
spec = importlib.util.spec_from_file_location("isolated_plan_validation", PLAN / "validate_plan.py")
|
|
validator = importlib.util.module_from_spec(spec)
|
|
spec.loader.exec_module(validator)
|
|
validator.PLAN = stage
|
|
validator.ROOT = ROOT
|
|
exit_code = 0
|
|
with redirect_stdout(io.StringIO()):
|
|
try:
|
|
validator.main()
|
|
except SystemExit as exc:
|
|
exit_code = exc.code
|
|
result = json.loads((stage / "plan_validation.json").read_text())
|
|
expected_result = (exit_code == 1 and expected in result["failed_checks"]) if expected else (exit_code == 0 and not result["failed_checks"])
|
|
return {"case": case, "exit_code": exit_code, "expected_guard": expected,
|
|
"expected_result": expected_result,
|
|
"failed_checks": result["failed_checks"]}
|
|
|
|
|
|
def main():
|
|
rows = [
|
|
exercise("unmodified_control", "progress_contract.json", lambda data: None, None),
|
|
exercise("unresolved_final_percentage", "progress_contract.json",
|
|
lambda data: data.update(total_game_acceptance_percent=1.0),
|
|
"unresolved_final_denominator_not_reported_as_total"),
|
|
exercise("stale_static_index_register", "current_evidence_links.json",
|
|
lambda data: data.update(atomic_register_sha256="0" * 64),
|
|
"evidence_index_register_pin_matches"),
|
|
exercise("unreviewed_atom_promoted_to_pass", "atomic_requirements.json",
|
|
lambda data: data["requirements"][0]["view_results"]["runtime"].update(state="pass"),
|
|
"unreviewed_atomic_views_remain_unverified"),
|
|
exercise("P03_whole_package_completed", "work_packages.json",
|
|
lambda data: next(row for row in data if row["id"] == "P03").update(state="completed"),
|
|
"P01_P03_not_whole_package_completed"),
|
|
]
|
|
report = {"scope": "plan-validator negative guards; isolated document copies, no game execution",
|
|
"checked_at_jst": datetime.now(ZoneInfo("Asia/Tokyo")).isoformat(),
|
|
"passed": all(row["expected_result"] for row in rows), "rows": rows,
|
|
"production_game_source_edits": 0, "new_engine_runs": 0}
|
|
(PLAN / "progress_validator_guard_checks.json").write_text(json.dumps(report, ensure_ascii=False, indent=2) + "\n")
|
|
print(json.dumps(report, ensure_ascii=False))
|
|
if not report["passed"]:
|
|
raise SystemExit(1)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|