1import os, sys, json, tempfile, pytest2sys.path.insert(0, os.path.join(os.path.dirname(__file__), "..", "..", "src"))3from pgar.state import StateStore4from pgar.contracts import RunManifest56def mk():7 d = tempfile.mkdtemp(); return StateStore(os.path.join(d, "s.sqlite"))89def test_create_and_idempotent():10 s = mk(); m = RunManifest("RD0001", "F2-smoke-01", "development", "A", 0)11 s.create_run(m)12 with pytest.raises(ValueError):13 s.create_run(m)14 assert s.get_run("RD0001")["status"] == "not_started"1516def test_transitions_validated():17 s = mk(); s.create_run(RunManifest("RD0002", "t", "development", "B", 0))18 with pytest.raises(ValueError):19 s.transition("RD0002", "completed") # not_started -> completed illegal20 s.transition("RD0002", "prepared"); s.transition("RD0002", "running"); s.transition("RD0002", "completed")21 with pytest.raises(ValueError):22 s.transition("RD0002", "evaluated") # invariant: no receipt23 s.transition("RD0002", "evaluated", evaluation_receipt="x.json")24 with pytest.raises(ValueError):25 s.transition("RD0002", "running") # terminal2627def test_freeze_blocks_updates():28 s = mk(); s.create_run(RunManifest("RD0003", "t", "confirmatory", "C", 0))29 s.transition("RD0003", "prepared"); s.transition("RD0003", "running"); s.transition("RD0003", "completed"); s.transition("RD0003", "evaluated", evaluation_receipt="r")30 assert s.freeze_split("confirmatory") == 131 with pytest.raises(PermissionError):32 s.update_manifest("RD0003", notes="x")3334def test_job_ledger_idempotent():35 s = mk(); assert s.log_job("k1", "RD", "execute") is True; assert s.log_job("k1", "RD", "execute") is False36