sched: bind ownership to store composition; stable recovery failure; schema-checked prepare; guarded settle (R4 wave 2)

This commit is contained in:
lda
2026-09-08 18:36:09 +07:00 Verified
parent b9d8eb9d16
commit 3f1d5d158b
16 changed files with 1299 additions and 60 deletions
+8 -8
View File
@@ -83,7 +83,7 @@ def test_poll_without_ownership_rejects_before_writes(tmp_path: Path) -> None:
calls.append(admission.id)
raise AssertionError("dispatcher must not run without ownership")
ownership = SchedulerOwnership(tmp_path / "sched", owner="never-acquired")
ownership = SchedulerOwnership(tmp_path, owner="never-acquired")
sched, store, runs = _scheduler(tmp_path, ownership)
sched.dispatcher = ScriptedDispatcher({"*": spy})
intended = ts(2026, 9, 8, 12, 0)
@@ -98,7 +98,7 @@ def test_poll_without_ownership_rejects_before_writes(tmp_path: Path) -> None:
def test_poll_with_released_ownership_rejects(tmp_path: Path) -> None:
ownership = SchedulerOwnership(tmp_path / "sched", owner="test").acquire()
ownership = SchedulerOwnership(tmp_path, owner="test").acquire()
sched, store, runs = _scheduler(tmp_path, ownership)
intended = ts(2026, 9, 8, 12, 0)
_due_setup(sched, store, intended)
@@ -133,7 +133,7 @@ def test_recover_without_ownership_rejects_before_writes(tmp_path: Path) -> None
schedule_revision=1,
)
materialize_admitted_view(store=run_store, admission=admission)
ownership = SchedulerOwnership(tmp_path / "sched", owner="never-acquired")
ownership = SchedulerOwnership(tmp_path, owner="never-acquired")
with pytest.raises(SecondOwnerError):
sched_recovery.recover(
schedule_store=sched_store,
@@ -146,7 +146,7 @@ def test_recover_without_ownership_rejects_before_writes(tmp_path: Path) -> None
def test_held_ownership_allows_poll_and_recovery(tmp_path: Path) -> None:
ownership = SchedulerOwnership(tmp_path / "sched", owner="test").acquire()
ownership = SchedulerOwnership(tmp_path, owner="test").acquire()
try:
sched, store, runs = _scheduler(tmp_path, ownership, script={"*": "hang"})
intended = ts(2026, 9, 8, 12, 0)
@@ -164,9 +164,9 @@ def test_held_ownership_allows_poll_and_recovery(tmp_path: Path) -> None:
def test_second_owner_cannot_acquire_for_poll(tmp_path: Path) -> None:
first = SchedulerOwnership(tmp_path / "sched", owner="first").acquire()
first = SchedulerOwnership(tmp_path, owner="first").acquire()
try:
second = SchedulerOwnership(tmp_path / "sched", owner="second")
second = SchedulerOwnership(tmp_path, owner="second")
with pytest.raises(SecondOwnerError):
second.acquire()
assert not second.held
@@ -181,7 +181,7 @@ def test_second_owner_cannot_acquire_for_poll(tmp_path: Path) -> None:
def test_admin_mutations_require_ownership(tmp_path: Path) -> None:
ownership = SchedulerOwnership(tmp_path / "sched", owner="test")
ownership = SchedulerOwnership(tmp_path, owner="test")
sched, store, _ = _scheduler(tmp_path, ownership)
store.create_schedule(_sched_model("a", paused=True))
with pytest.raises(SecondOwnerError):
@@ -193,7 +193,7 @@ def test_admin_mutations_require_ownership(tmp_path: Path) -> None:
def test_settle_requires_ownership(tmp_path: Path) -> None:
ownership = SchedulerOwnership(tmp_path / "sched", owner="test").acquire()
ownership = SchedulerOwnership(tmp_path, owner="test").acquire()
try:
sched, store, runs = _scheduler(tmp_path, ownership, script={"*": "hang"})
intended = ts(2026, 9, 8, 12, 0)