fix: exclude foreign-claimed work from allocation instead of blockading the queue (Closes #765)
Recovered preserved candidate d06198b onto current master 0c2f45a via clean
cherry-pick. Active foreign leases are excluded before allocator ranking;
controller_instance_id ownership is persisted; dashboard matches allocator
exclusion. Stable patch-id bacafc5f… preserved.
Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
This commit is contained in:
+40
-4
@@ -14,7 +14,7 @@ Design rules:
|
||||
from __future__ import annotations
|
||||
|
||||
from dataclasses import dataclass, field
|
||||
from typing import Any, Iterable, Sequence
|
||||
from typing import Any, Iterable, Mapping, Sequence
|
||||
|
||||
from allocator_service import (
|
||||
ROLE_AUTHOR,
|
||||
@@ -22,7 +22,11 @@ from allocator_service import (
|
||||
ROLE_MERGER,
|
||||
ROLE_RECONCILER,
|
||||
ROLE_REVIEWER,
|
||||
OWNERSHIP_FOREIGN,
|
||||
OWNERSHIP_UNKNOWN,
|
||||
SKIP_CLAIMED_BY_OTHER_SESSION,
|
||||
WorkCandidate,
|
||||
classify_claim_ownership,
|
||||
classify_skip,
|
||||
expected_role_for_candidate,
|
||||
sort_candidates,
|
||||
@@ -265,9 +269,13 @@ def _entry_for_candidate(
|
||||
c: WorkCandidate,
|
||||
*,
|
||||
terminal_pr: int | None,
|
||||
claim_ownership: str | None = None,
|
||||
) -> QueueEntry:
|
||||
expected = expected_role_for_candidate(c)
|
||||
badges = _badges_for_candidate(c, terminal_pr=terminal_pr)
|
||||
claimed_by_other = claim_ownership in (OWNERSHIP_FOREIGN, OWNERSHIP_UNKNOWN)
|
||||
if claimed_by_other and "claimed" not in badges:
|
||||
badges = tuple(list(badges) + ["claimed"])
|
||||
safe_roles: list[str] = []
|
||||
block_reason: str | None = None
|
||||
|
||||
@@ -276,6 +284,12 @@ def _entry_for_candidate(
|
||||
block_reason = "status blocked"
|
||||
elif c.dependency_unmet:
|
||||
block_reason = c.dependency_reason or "unmet dependency"
|
||||
elif claimed_by_other:
|
||||
# #765: never advertise another controller's active task as safe work.
|
||||
block_reason = (
|
||||
f"{SKIP_CLAIMED_BY_OTHER_SESSION}: active lease held by another "
|
||||
"controller"
|
||||
)
|
||||
elif c.already_claimed_elsewhere:
|
||||
block_reason = "already claimed elsewhere"
|
||||
elif c.kind == "pr" and not (c.head_sha or "").strip():
|
||||
@@ -291,7 +305,12 @@ def _entry_for_candidate(
|
||||
|
||||
if block_reason is None:
|
||||
# Safe only for the expected role, and only when classify_skip agrees.
|
||||
skip = classify_skip(c, role=expected, terminal_pr=terminal_pr)
|
||||
skip = classify_skip(
|
||||
c,
|
||||
role=expected,
|
||||
terminal_pr=terminal_pr,
|
||||
claim_ownership=claim_ownership,
|
||||
)
|
||||
if skip is None:
|
||||
safe_roles.append(expected)
|
||||
else:
|
||||
@@ -450,8 +469,16 @@ def build_workflow_dashboard(
|
||||
terminal_lock: dict[str, Any] | None = None,
|
||||
inventory_complete: bool = True,
|
||||
inventory_reasons: Sequence[str] | None = None,
|
||||
claims: Mapping[tuple[str, int], dict[str, Any]] | None = None,
|
||||
session_id: str | None = None,
|
||||
controller_instance_id: str | None = None,
|
||||
) -> DashboardSnapshot:
|
||||
"""Build a full dashboard snapshot from injected inventory (pure)."""
|
||||
"""Build a full dashboard snapshot from injected inventory (pure).
|
||||
|
||||
*claims* (#765) maps ``(kind, number)`` to the live lease holding that work
|
||||
item. Items claimed by a different controller are never presented as safe
|
||||
next work for this one.
|
||||
"""
|
||||
reasons = [str(r) for r in (inventory_reasons or ()) if str(r).strip()]
|
||||
if not inventory_complete:
|
||||
reasons.append(
|
||||
@@ -461,7 +488,16 @@ def build_workflow_dashboard(
|
||||
|
||||
ranked = sort_candidates(list(candidates))
|
||||
entries = [
|
||||
_entry_for_candidate(c, terminal_pr=terminal_pr) for c in ranked
|
||||
_entry_for_candidate(
|
||||
c,
|
||||
terminal_pr=terminal_pr,
|
||||
claim_ownership=classify_claim_ownership(
|
||||
(claims or {}).get((c.kind, int(c.number))),
|
||||
session_id=session_id,
|
||||
controller_instance_id=controller_instance_id,
|
||||
),
|
||||
)
|
||||
for c in ranked
|
||||
]
|
||||
|
||||
open_prs = [e for e in entries if e.kind == "pr"]
|
||||
|
||||
Reference in New Issue
Block a user