fix(reconcile): safely resolve worktree bindings whose paths are missing (Closes #970)

This commit is contained in:
2026-07-29 05:43:52 -04:00
parent 956fa15fe3
commit 3f584352df
5 changed files with 1074 additions and 0 deletions
+111
View File
@@ -1913,6 +1913,88 @@ class ControlPlaneDB:
),
)
def retire_lease_worktree_path(
self,
lease_id: str,
*,
expected_path: str | None = None,
reason: str = "missing_worktree_path_retired",
) -> dict[str, Any]:
"""Retire a missing worktree_path binding from a control-plane lease (#970).
Clears worktree_path on the lease row, updates provenance_json with
durable retirement audit proof, and writes a worktree_binding_retired event.
Fail closed: if expected_path is provided and does not match current
worktree_path, the update is refused to prevent racing mutations.
"""
now_s = _ts()
with self._tx() as conn:
cols = self._lease_columns(conn)
row = conn.execute(
"SELECT * FROM leases WHERE lease_id = ?",
(lease_id,),
).fetchone()
if not row:
raise ControlPlaneError(f"unknown lease_id {lease_id}")
current_wt = (dict(row).get("worktree_path") or "").strip()
if expected_path and current_wt and os.path.realpath(current_wt) != os.path.realpath(expected_path):
raise ControlPlaneError(
f"cannot retire lease {lease_id} worktree_path: expected '{expected_path}' "
f"does not match current '{current_wt}' (fail closed)"
)
# Parse and update provenance_json
raw_prov = dict(row).get("provenance_json") or "{}"
try:
prov = json.loads(raw_prov) if isinstance(raw_prov, str) else dict(raw_prov)
except Exception:
prov = {}
if not isinstance(prov, dict):
prov = {}
prior_path = current_wt or prov.get("worktree_path")
prov.update({
"worktree_path_retired": True,
"retired_worktree_path": prior_path,
"retired_at": now_s,
"retirement_reason": reason,
"worktree_path": "",
})
prov_json = json.dumps(prov)
if "worktree_path" in cols:
conn.execute(
"UPDATE leases SET worktree_path = '', provenance_json = ? WHERE lease_id = ?",
(prov_json, lease_id),
)
else:
conn.execute(
"UPDATE leases SET provenance_json = ? WHERE lease_id = ?",
(prov_json, lease_id),
)
conn.execute(
"""
INSERT INTO events(work_item_id, event_type, message, created_at)
VALUES (?, 'worktree_binding_retired', ?, ?)
""",
(
row["work_item_id"],
f"lease {lease_id} worktree_path '{prior_path}' retired: {reason}",
now_s,
),
)
return {
"lease_id": lease_id,
"retired": True,
"prior_worktree_path": prior_path,
"retired_at": now_s,
"reason": reason,
}
def abandon_lease(
self,
*,
@@ -3051,3 +3133,32 @@ class ControlPlaneDB:
"live_lease_id": None if live_lease_id is None else str(live_lease_id),
"reconcile_action": "reconcile_required" if stale else "safe_to_resume",
}
def retire_session_checkpoint_worktree_path(
self,
session_id: str,
*,
checkpoint_id: str | None = None,
expected_path: str | None = None,
reason: str = "missing_worktree_path_retired",
) -> dict[str, Any]:
"""Retire a missing worktree_path from session_checkpoints (#970)."""
now_s = _ts()
with self._tx() as conn:
if checkpoint_id:
conn.execute(
"UPDATE session_checkpoints SET worktree_path = '', updated_at = ? WHERE checkpoint_id = ?",
(now_s, checkpoint_id),
)
elif session_id:
conn.execute(
"UPDATE session_checkpoints SET worktree_path = '', updated_at = ? WHERE session_id = ?",
(now_s, session_id),
)
return {
"session_id": session_id,
"checkpoint_id": checkpoint_id,
"retired": True,
"retired_at": now_s,
"reason": reason,
}