feat: first-class control-plane lease lifecycle (Closes #601)
Make active leases queryable workflow state with canonical adopt, release, expire/reclaim, and abandon operations on the #613 control-plane DB substrate. - lease_lifecycle.py: policy, proof gates, safe_next_action vocabulary - control_plane_db: schema v3 provenance columns + list/inspect/adopt/abandon - MCP tools: gitea_*_workflow_lease(s) for list/inspect/adopt/release/expire/abandon/reclaim - issue_lock_store: sanctioned reclaim of expired author locks (dead pid / missing wt) - Tests cover lifecycle, foreign steal refusal, allocator compatibility, merger handoff
This commit is contained in:
@@ -103,20 +103,40 @@ class TestIssueLockStore(unittest.TestCase):
|
||||
self.assertIn("live foreign issue lock", block or "")
|
||||
|
||||
def test_expired_lease_allows_takeover_with_conflict_check(self):
|
||||
# #601: expired + dead pid / missing worktree → sanctioned reclaim (no block).
|
||||
existing = _lock_record(
|
||||
branch_name="feat/issue-420-other",
|
||||
worktree_path="/tmp/other",
|
||||
worktree_path="/tmp/other-does-not-exist-420",
|
||||
session_pid=1,
|
||||
work_lease=_lease("2000-01-01T00:00:00Z"),
|
||||
)
|
||||
incoming = _lock_record(worktree_path="/tmp/mine")
|
||||
self.assertIsNone(ils.assess_foreign_lock_overwrite(existing, incoming))
|
||||
block = ils.assess_same_issue_lease_conflict(
|
||||
existing,
|
||||
issue_number=420,
|
||||
branch_name="feat/issue-420-server-code-parity",
|
||||
worktree_path="/tmp/mine",
|
||||
with mock.patch.object(ils, "is_process_alive", return_value=False):
|
||||
block = ils.assess_same_issue_lease_conflict(
|
||||
existing,
|
||||
issue_number=420,
|
||||
branch_name="feat/issue-420-server-code-parity",
|
||||
worktree_path="/tmp/mine",
|
||||
)
|
||||
self.assertIsNone(block)
|
||||
|
||||
# Expired but still-live owner pid AND present worktree → fail closed.
|
||||
present_wt = self.lock_dir # exists
|
||||
sticky = _lock_record(
|
||||
branch_name="feat/issue-420-other",
|
||||
worktree_path=present_wt,
|
||||
session_pid=os.getpid(),
|
||||
work_lease=_lease("2000-01-01T00:00:00Z"),
|
||||
)
|
||||
self.assertIn("Recovery review is required", block or "")
|
||||
with mock.patch.object(ils, "is_process_alive", return_value=True):
|
||||
blocked = ils.assess_same_issue_lease_conflict(
|
||||
sticky,
|
||||
issue_number=420,
|
||||
branch_name="feat/issue-420-server-code-parity",
|
||||
worktree_path="/tmp/mine",
|
||||
)
|
||||
self.assertIn("Recovery review is required", blocked or "")
|
||||
|
||||
def test_same_owner_lease_conflict_allows_refresh(self):
|
||||
worktree = "/tmp/wt-420"
|
||||
|
||||
Reference in New Issue
Block a user