fix: bug: dev-poll stale detection races with issue_claim — blocks freshly claimed issues (#471)
Add 60-second grace period to stale in-progress detection in dev-poll.sh. When a poller sees an in-progress issue with no assignee/PR/lock, it now checks the timeline API for when the label was added. If <60s ago, it skips stale detection to allow the claiming agent time to finish its assign+label sequence. Also documents the intentional assign-before-label ordering in issue_claim() that minimizes the race window. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
9d0b7f2b07
commit
8679332756
2 changed files with 43 additions and 4 deletions
|
|
@ -103,6 +103,37 @@ is_blocked() {
|
|||
# STALENESS DETECTION FOR IN-PROGRESS ISSUES
|
||||
# =============================================================================
|
||||
|
||||
# Check if in-progress label was added recently (within grace period).
|
||||
# Prevents race where a poller marks an issue as stale before the claiming
|
||||
# agent's assign + label sequence has fully propagated. See issue #471.
|
||||
# Args: issue_number [grace_seconds]
|
||||
# Returns: 0 if recently added (within grace period), 1 if not
|
||||
in_progress_recently_added() {
|
||||
local issue="$1" grace="${2:-60}"
|
||||
local now label_ts delta
|
||||
|
||||
now=$(date +%s)
|
||||
|
||||
# Query issue timeline for the most recent in-progress label event
|
||||
label_ts=$(curl -sf -H "Authorization: token ${FORGE_TOKEN}" \
|
||||
"${API}/issues/${issue}/timeline" | \
|
||||
jq -r '[.[] | select(.type == "label") | select(.label.name == "in-progress")] | last | .created_at // empty') || true
|
||||
|
||||
if [ -z "$label_ts" ]; then
|
||||
return 1 # no label event found — not recently added
|
||||
fi
|
||||
|
||||
# Convert ISO timestamp to epoch and compare
|
||||
local label_epoch
|
||||
label_epoch=$(date -d "$label_ts" +%s 2>/dev/null || echo 0)
|
||||
delta=$(( now - label_epoch ))
|
||||
|
||||
if [ "$delta" -lt "$grace" ]; then
|
||||
return 0 # within grace period
|
||||
fi
|
||||
return 1
|
||||
}
|
||||
|
||||
# Check if there's an open PR for a specific issue
|
||||
# Args: issue_number
|
||||
# Returns: 0 if open PR exists, 1 if not
|
||||
|
|
@ -460,9 +491,15 @@ if [ "$ORPHAN_COUNT" -gt 0 ]; then
|
|||
fi
|
||||
|
||||
if [ "$OPEN_PR" = false ] && [ "$BLOCKED_BY_INPROGRESS" = false ]; then
|
||||
log "issue #${ISSUE_NUM} is stale (no assignee, no open PR, no agent lock) — relabeling to blocked"
|
||||
relabel_stale_issue "$ISSUE_NUM" "no_assignee_no_open_pr_no_lock"
|
||||
BLOCKED_BY_INPROGRESS=true
|
||||
# Grace period: skip if in-progress label was added <60s ago (issue #471)
|
||||
if in_progress_recently_added "$ISSUE_NUM" 60; then
|
||||
log "issue #${ISSUE_NUM} in-progress label added <60s ago — skipping stale detection (grace period)"
|
||||
BLOCKED_BY_INPROGRESS=true
|
||||
else
|
||||
log "issue #${ISSUE_NUM} is stale (no assignee, no open PR, no agent lock) — relabeling to blocked"
|
||||
relabel_stale_issue "$ISSUE_NUM" "no_assignee_no_open_pr_no_lock"
|
||||
BLOCKED_BY_INPROGRESS=true
|
||||
fi
|
||||
fi
|
||||
|
||||
# Formula guard: formula-labeled issues should not be worked on by dev-agent.
|
||||
|
|
|
|||
|
|
@ -102,7 +102,9 @@ issue_claim() {
|
|||
return 1
|
||||
fi
|
||||
|
||||
# Assign to self (Forgejo rejects if already assigned differently)
|
||||
# Assign to self BEFORE adding in-progress label (issue #471).
|
||||
# This ordering ensures the assignee is set by the time other pollers
|
||||
# see the in-progress label, reducing the stale-detection race window.
|
||||
curl -sf -X PATCH \
|
||||
-H "Authorization: token ${FORGE_TOKEN}" \
|
||||
-H "Content-Type: application/json" \
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue