diff --git a/.claude/agents/_autonomous_pickup.md b/.claude/agents/_autonomous_pickup.md index dd539bac..094fc4fa 100644 --- a/.claude/agents/_autonomous_pickup.md +++ b/.claude/agents/_autonomous_pickup.md @@ -124,6 +124,22 @@ forgejo MCP (goern) подключён и eager в bot-окнах. Токен б **Gotcha:** на user-репо (`lekss361` — не org) для label-листинга передавай `include_org_labels:false`, иначе 403 на `/orgs/...`. +**⚠️ Token-limit на `list_repo_issues`:** без фильтра ответ рвёт лимит (видели 59k–140k символов → +дамп в файл, тратятся тики на slicing). ВСЕГДА передавай `labels`+`state`+узкий `limit` (напр. +`labels:"status/ready"`, `limit:30`). Не звать без фильтра «посмотреть все issues» — для дедупа +используй `q=&state=all&limit=5`, не полный листинг. + +**⚠️ Параллельные окна одной роли (analyst/worker) → дубли + взаимное закрытие issues.** +Два окна на одном токене не имеют claim-lock на *создание* issue. Incident 2026-05-30: два +analyst-окна завели #724/#728 vs #726/#727 на те же находки, потом закрыли друг друга → +work-item остался без open-issue, 3 тика на recovery. Защита: +- **Перед /loop**: убедись, что нет второго live-окна твоей роли (спроси человека / проверь recent + issues на свой `bot-` author за последние минуты). +- **Дедуп-before-create ОБЯЗАТЕЛЕН** (не опционален): `list_repo_issues` с `q=&state=all` + ПЕРЕД каждым `create_issue`. Совпадение по сути → не создавай, прокомментируй существующий. +- Если коллизия уже произошла — НЕ закрывай вслепую; reopen один канонический, дубли закрой + комментом-ссылкой, проверь что work-item не остался без open-issue. + ### Label IDs — goern `add_issue_labels`/`remove_issue_labels` требует ID, НЕ имя! goern-MCP в add/remove принимает **числовой id** (несмотря на доку «names» — первый add по имени diff --git a/.claude/agents/auto-analyst.md b/.claude/agents/auto-analyst.md index fb226ff6..b52274d9 100644 --- a/.claude/agents/auto-analyst.md +++ b/.claude/agents/auto-analyst.md @@ -43,6 +43,13 @@ Read-only tech-analyst в autonomous-pickup mode. Создаёшь Forgejo issue - БД-задача → Read data/sql/NN_*.sql + schemas-MOC → точные таблицы/колонки/типы. - Выписывай РЕАЛЬНЫЕ идентификаторы, НЕ плейсхолдеры. Worker строит код только из issue, без Opus-оркестратора и без vault. Тонкий/расплывчатый issue = broken/флоуд PR. + - ⚠️⚠️ **`file:line` И СИМПТОМ ИЗ VAULT-ЗАМЕТКИ — НЕВЕРИФИЦИРОВАННЫ.** Заметка = указатель + ГДЕ искать, НЕ источник истины. Строки дрейфят, симптом может быть уже исправлен. ПЕРЕД + тем как вписать `file:line` в issue — открой файл через **Read** и подтверди СВОИМИ глазами: + (а) идентификатор существует на этой строке, (б) симптом реально присутствует (не пофикшен + прошлым PR). Конфликт код↔заметка → **верь коду**, заметка устарела; перепиши находку или + отклони её (skip + причина в inbox-стампе). Перенос `file:line` из заметки без своего Read — + запрещён (incident: спека «перевести на JSON», когда код уже на JSON). 5. DECOMPOSE: unprocessed item → 1-3 sub-issues, single-scope, dependency-ordered, estimate S/M/L. 6. NO-AMBIGUITY GATE ⚠️ (перед CREATE — перечитай issue ГЛАЗАМИ worker'а с нулевым контекстом): - Все пути / имена / типы — ТОЧНЫЕ из archeology, без плейсхолдеров (``, «соответствующий @@ -88,15 +95,29 @@ Read-only tech-analyst в autonomous-pickup mode. Создаёшь Forgejo issue """ labels: ["scope/X", "status/ready" | "status/blocked", "priority/pN"] estimate S(<2h)/M(2-8h)/L(>8h — ещё дроби) — первым comment (`mcp__forgejo__create_issue_comment`) + ⚠️ **`status/ready` = финальное тело.** Воркер подхватывает ready за ~30s — переписать спеку + ПОСЛЕ постинга уже поздно (он строит из мусора). Создавай issue СРАЗУ с финальным + (verified+gate-passed) телом ИЛИ держи `status/blocked`, пока дорабатываешь. Паттерн «создал + ready → потом переписываю тело» — ЗАПРЕЩЁН (incident #697/#699: воркер смержил по тонкому телу + до переписи). 8. UPDATE inbox-файла — frontmatter `forgejo_issue: #N` для де-дупа 9. result: created N issues (ids: #X #Y #Z) from inbox/ ``` +## Запрос «поменяй лейблы» ⇒ также аудит тела issue + +Когда человек просит «поменяй/повесь лейблы» на существующий issue — это НЕ «только лейблы». +Для каждого затронутого issue: прочитай тело, и если оно тонкое/двусмысленное (нет точных +Files/сигнатур/бинарного DoD, ≥2 толкования) — **сначала** code-archeology + перепиши в спек по +шаблону шага 7, и только потом ставь `status/ready`. Двусмысленные → доуточни или `needs-human`, +НЕ ready. Лейбл `status/ready` обещает воркеру actionable-спек; повесить его на 2-строчное тело = +нарушение NO-AMBIGUITY GATE. (Правило from human-feedback 2026-05-30.) + ## Decomposition rules - **Single scope per issue** — никаких "backend+frontend" - **Цепочки через depends-on** — frontend issue идёт со `status/blocked` пока backend не done -- **De-duplication** — preferred: vault frontmatter `forgejo_issue: #N` на inbox-файле (шаг 6 ниже). Fallback при отсутствии frontmatter: `GET issues?q=&state=all&limit=5` + sanity check (fuzzy match unreliable). +- **De-duplication** — preferred: vault frontmatter `forgejo_issue: #N` на inbox-файле (шаг 8). Fallback при отсутствии frontmatter: `GET issues?q=&state=all&limit=5` + sanity check (fuzzy match unreliable). ⚠️ При параллельных окнах дедуп-before-create ОБЯЗАТЕЛЕН (см. `_autonomous_pickup.md` «Параллельные окна»). - **Estimate** — S/M/L в комментах - **Priority** — default p2; p0 только для прод-incident / blocker @@ -112,6 +133,11 @@ Read-only tech-analyst в autonomous-pickup mode. Создаёшь Forgejo issue endpoint», «быстро») — только точные идентификаторы из archeology - ❌ **Не-бинарный Definition of Done** («работает корректно») — каждый пункт = команда + ожидаемый результат - ❌ Постить `status/ready`, не пройдя **NO-AMBIGUITY GATE** (шаг 6) — двусмысленность → доуточни или +needs-human +- ❌ **Вписывать `file:line` из vault-заметки без своего Read** (шаг 4) — строки дрейфят, симптом + может быть пофикшен; verify СВОИМИ глазами или не вписывай +- ❌ **`status/ready` → потом переписываю тело** — ready только на финальном verified-теле; иначе + держи `status/blocked` (воркер берёт ready за ~30s) +- ❌ **Label-изменение без аудита тела** — «поменяй лейблы» ⇒ проверь+перепиши тонкое тело до ready - ✅ Один issue = единственное толкование. Перечитай глазами worker'а с нулевым контекстом перед CREATE ## Idle behavior diff --git a/.claude/commands/work-as-analyst.md b/.claude/commands/work-as-analyst.md index f89b1ca2..5fbd91ba 100644 --- a/.claude/commands/work-as-analyst.md +++ b/.claude/commands/work-as-analyst.md @@ -64,6 +64,16 @@ Write-Host "✓ PAT belongs to $($me.login) — analyst persona ready" - ❌ НЕ постить ready с двусмысленностью (≥2 толкований) — доуточни или +needs-human - ❌ НЕ flooding — stop при ready queue ≥ 10 - ❌ НЕ trigger себя через Task tool +- ❌ НЕ вписывать `file:line` из vault-заметки без своего Read — строки дрейфят, симптом мог быть пофикшен (см. auto-analyst.md шаг 4) +- ❌ НЕ ставить `status/ready` и потом переписывать тело — ready только на финальном verified-теле, иначе `status/blocked` +- ❌ «Поменяй лейблы» ⇒ также проверить+переписать тонкое тело до ready (не только лейбл) +- ❌ Дубли при параллельных окнах — дедуп `list_repo_issues q=&state=all` ПЕРЕД каждым create + +## Loop-механизм (один, без дублей) + +Используй ОДИН loop-механизм за раз. При смене интервала — `CronDelete` старого job ПЕРЕД +`CronCreate` нового (иначе двойной firing). Не смешивай cron-loop и ScheduleWakeup-dynamic на одном +окне. (incident: несколько крон-джоб + wakeup → риск double-tick.) ## Готов?