diff --git a/desloppify/engine/_plan/auto_cluster.py b/desloppify/engine/_plan/auto_cluster.py index 947fa6df9..ea8b1685a 100644 --- a/desloppify/engine/_plan/auto_cluster.py +++ b/desloppify/engine/_plan/auto_cluster.py @@ -163,13 +163,16 @@ def _evictable_auto_cluster_issue_ids(plan: PlanModel) -> set[str]: active_ids: set[str] = set() inactive_ids: set[str] = set() for cluster in plan.get("clusters", {}).values(): - if not isinstance(cluster, dict) or not cluster.get("auto"): + if not isinstance(cluster, dict): continue ids = { issue_id for issue_id in cluster.get("issue_ids", []) if isinstance(issue_id, str) and issue_id and not is_synthetic_id(issue_id) } + if not cluster.get("auto"): + active_ids |= ids + continue if cluster_is_active(cluster): active_ids |= ids else: diff --git a/desloppify/tests/plan/test_queue_metadata.py b/desloppify/tests/plan/test_queue_metadata.py index a12c06927..d8e2cb811 100644 --- a/desloppify/tests/plan/test_queue_metadata.py +++ b/desloppify/tests/plan/test_queue_metadata.py @@ -229,6 +229,30 @@ def test_cross_cluster_move_not_evicted() -> None: assert evicted == {"old_only"} +def test_manual_cluster_member_not_evicted_from_inactive_auto_cluster() -> None: + from desloppify.engine._plan.auto_cluster import ( + _evictable_auto_cluster_issue_ids, + ) + + plan = { + "clusters": { + "auto/exports": { + "auto": True, + "issue_ids": ["u1", "u2"], + "execution_status": EXECUTION_STATUS_REVIEW, + "execution_policy": EXECUTION_POLICY_PLANNED_ONLY, + }, + "manual/my-task": { + "auto": False, + "issue_ids": ["u1"], + "execution_status": EXECUTION_STATUS_ACTIVE, + }, + }, + } + evicted = _evictable_auto_cluster_issue_ids(plan) + assert evicted == {"u2"} + + # ── explain_queue ──────────────────────────────────────────────────