gendesign/.claude/agents/_autonomous_pickup.md
lekss361 76784e91fd
Some checks failed
CI / backend (pull_request) Failing after 43s
CI / frontend (pull_request) Successful in 1m35s
fixup(claude): address review-bot findings on PR #608
🟠 High:
- auto-backend.md: drop execute_sql из tools (DDL/DML blast radius)
- auto-code-reviewer.md: drop execute_sql + add analyze_query_indexes
- _autonomous_pickup.md: env vars FORGEJO_PAT/BASE_URL → FORGEJO_TOKEN/URL (align с rules/git-pr.md)
- auto-code-reviewer.md: добавлен canonical marker template
  <!-- gendesign-review-bot: sha=X verdict=Y --> + SHA guard перед merge
- auto-code-reviewer.md: self-extending guard exception (NEVER merge PRs
  меняющие git-pr.md auto-merge policy / CLAUDE.md critical rules /
  этот файл / содержащие литеральные secrets)

🟡 Medium:
- _autonomous_pickup.md: STRICT claim race check (length==1 AND assignee==me)
  + best-effort rollback при race lost
- _autonomous_pickup.md: pause-bots mid-work policy (finish current, не abort)
- _autonomous_pickup.md: stale-claim cron explicitly marked TODO
- auto-qa-tester.md: differentiate flaky/prod_down/feature_regression — global
  pause только при prod_down (3× FAIL на /health endpoint), не на flaky
- auto-backend.md: PR body template из rules/git-pr.md (Summary + Test plan + Closes)

🟢 Low:
- _autonomous_pickup.md: BOT_USERNAME documented в env list
- _autonomous_pickup.md: PAT scope guidance (narrow repo, не user-scope)
- auto-analyst.md: de-dup через forgejo_issue frontmatter preferred (fuzzy
  query — fallback)

Refs: PR #608 review by @lekss361 (gendesign-review-bot marker)
2026-05-27 23:11:58 +03:00

146 lines
6.7 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

---
name: _autonomous_pickup
description: "[SHARED SNIPPET — do not invoke directly] Forgejo queue pickup logic, импортируется во все auto-*.md агенты. Содержит claim/state-transition contract."
status: draft
created_at: 2026-05-27
---
# Autonomous queue pickup — shared contract
> **NOT a standalone agent.** Этот файл — общая инструкция, которую копи-пастят
> внутрь каждого `auto-*.md`. Содержит claim/lifecycle/kill-switch логику.
## Forgejo API endpoints (на основе bot-PAT в окружении)
```bash
# Environment vars (align с .claude/rules/git-pr.md + existing infrastructure):
# FORGEJO_URL=https://git.gendsgn.ru # БЕЗ /api/v1 — добавляется ниже
# FORGEJO_TOKEN=<bot's PAT> # narrow scope: ТОЛЬКО repo lekss361/gendesign
# # (write:issue, write:repository), НЕ user-scope
# FORGEJO_REPO=lekss361/gendesign
# BOT_USERNAME=<bot's login> # для claim/assign — должен matches тому, кто owns FORGEJO_TOKEN
#
# Проверка credentials при запуске окна:
# curl -sS -H "Authorization: token $FORGEJO_TOKEN" "$FORGEJO_URL/api/v1/user" | jq .login
# = должен вернуть $BOT_USERNAME
curl_forgejo() {
curl -sS -H "Authorization: token $FORGEJO_TOKEN" \
-H "Content-Type: application/json" \
"$FORGEJO_URL/api/v1/$1" "${@:2}"
}
```
## Kill-switch check (выполняй ПЕРВЫМ делом в каждом /loop tick)
```bash
# Проверка через meta-issue с label "pause-bots"
if curl_forgejo "repos/$FORGEJO_REPO/issues?labels=pause-bots&state=open&limit=1" \
| jq -e 'length > 0' > /dev/null; then
echo "result: paused (pause-bots active)"
exit 0 # /loop спит до следующего тика
fi
```
## Pickup query — по scope
```bash
SCOPE="backend" # ∈ {backend, frontend, db, qa, devops}
NEXT=$(curl_forgejo \
"repos/$FORGEJO_REPO/issues?state=open&labels=scope/$SCOPE,status/ready&assigned_to=none&sort=newest&limit=1" \
| jq -r '.[0] | if . then [.number, .title] | @tsv else "" end')
if [[ -z "$NEXT" ]]; then
echo "result: idle, no work for scope/$SCOPE"
exit 0
fi
```
## Claim — atomic-ish через label transition
> **Race window note**: Forgejo не поддерживает conditional-update (ETag/If-Match
> для issue PATCH). Между шагом 1 и 3 другой worker теоретически может тоже claim'нуть.
> Verify checks `length == 1 AND .assignees[0] == me` — иначе откатываемся.
```bash
ISSUE=$(echo "$NEXT" | cut -f1)
# 1. Assign self (atomic на стороне Forgejo для самого set-assignees, но не для transition)
curl_forgejo "repos/$FORGEJO_REPO/issues/$ISSUE" -X PATCH \
-d "{\"assignees\": [\"$BOT_USERNAME\"]}"
# 2. Transition ready → wip
curl_forgejo "repos/$FORGEJO_REPO/issues/$ISSUE/labels" -X POST \
-d '{"labels": ["status/wip"]}'
curl_forgejo "repos/$FORGEJO_REPO/issues/$ISSUE/labels/status/ready" -X DELETE
# 3. Verify claim не перехвачен — STRICT check
ISSUE_JSON=$(curl_forgejo "repos/$FORGEJO_REPO/issues/$ISSUE")
ASSIGNEE_COUNT=$(echo "$ISSUE_JSON" | jq '.assignees | length')
ASSIGNEE=$(echo "$ISSUE_JSON" | jq -r '.assignees[0].login // ""')
if [[ "$ASSIGNEE_COUNT" != "1" || "$ASSIGNEE" != "$BOT_USERNAME" ]]; then
echo "result: lost race for #$ISSUE (assignees=$ASSIGNEE_COUNT, first=$ASSIGNEE) — releasing"
# Best-effort rollback — снять wip, вернуть ready (не критично если не получится)
curl_forgejo "repos/$FORGEJO_REPO/issues/$ISSUE/labels" -X POST \
-d '{"labels": ["status/ready"]}'
curl_forgejo "repos/$FORGEJO_REPO/issues/$ISSUE/labels/status/wip" -X DELETE
exit 0
fi
```
## State transitions reference
| От → К | Кто переключает | Условие |
|---|---|---|
| (new) → `status/ready` | auto-analyst | issue декомпозирован, deps удовлетворены |
| `status/ready``status/wip` | auto-backend / auto-frontend | claim успешный |
| `status/wip``status/review` | worker | PR открыт |
| `status/review``status/qa` | auto-code-reviewer | APPROVE + merge |
| `status/review``status/blocked` | auto-code-reviewer | BLOCK/FIX verdict |
| `status/qa``status/done` | auto-qa-tester | smoke OK, issue closed |
| `status/qa``status/blocked` | auto-qa-tester | smoke FAIL |
| `status/blocked``status/ready` | **only human** | manual unblock |
| любой + `pause-bots` присутствует | (никто не работает) | kill-switch |
## Pause-bots поведение mid-work
Если `pause-bots` label появился ПОКА worker уже в wip:
1. **НЕ abort** — finish текущий commit + push (минимизирует потерю работы)
2. Open PR как обычно → PR попадёт в queue `status/review` (но reviewer тоже paused → PR не merge'нётся)
3. result: PR #N opened, then paused due to kill-switch
4. После un-pause — reviewer подхватит PR
Это **НЕ release claim** на исходный issue — он остаётся wip+assigned до merge.
## Stale-claim cleanup — TODO (отдельный PR / cron)
> ⚠️ **НЕ имплементировано в текущем PR.** Без stale cleanup worker crash =
> issue застрянет в `status/wip` forever. До имплементации — мониторь вручную.
```bash
# Каждые 30 минут — освобождать issues застрявшие в wip >4h
curl_forgejo "repos/$FORGEJO_REPO/issues?labels=status/wip&state=open" \
| jq -r '.[] | select(.updated_at < (now - 4*3600 | todate)) | .number' \
| while read i; do
curl_forgejo "repos/$FORGEJO_REPO/issues/$i" -X PATCH -d '{"assignees": []}'
curl_forgejo "repos/$FORGEJO_REPO/issues/$i/labels" -X POST -d '{"labels":["status/ready"]}'
curl_forgejo "repos/$FORGEJO_REPO/issues/$i/labels/status/wip" -X DELETE
done
```
## Self-throttle rules
1. **3 итерации подряд idle**`sleep = min(current * 1.5, 60m)`
2. **3 итерации подряд success**`sleep = max(current * 0.8, 5m)`
3. **24h ничего не закрыл** → result: idle 24h, эскалация (label `needs-human`)
## Error escalation
| Ошибка | Действие |
|---|---|
| HTTP 401/403 от Forgejo | PAT истёк / отозван → result: AUTH_ERROR, остановка окна |
| HTTP 500 от Forgejo | result: forgejo down, sleep 30m |
| Subagent error 3× на одной issue | +status/blocked +needs-human, отпустить assignee, next issue |