diff --git a/.opencode/skills/bug-discovery/SKILL.md b/.opencode/skills/bug-discovery/SKILL.md index 3933c93..119abfd 100644 --- a/.opencode/skills/bug-discovery/SKILL.md +++ b/.opencode/skills/bug-discovery/SKILL.md @@ -10,6 +10,6 @@ If a bug is found during work that is outside the scope of the current task: 1. Check `gh issue list` for duplicates. 2. Create a GitHub issue via `create-issue` tool (NOT raw `gh issue create`). 3. Title: `fix(scope): short description` in English. -4. Body: `## Контекст` / `## Задача` / `## Критерии приемки` (in Russian). +4. Body: `## Контекст` / `## Задача` / `## Контракты` / `## Инварианты` / `## Граничные случаи` / `## Вне scope` / `## Критерии приемки` (in Russian). 5. Continue the current task. Do NOT fix the bug yourself. 6. Report to orchestrator: "Created issue #N: ...". \ No newline at end of file diff --git a/.opencode/skills/issue/SKILL.md b/.opencode/skills/issue/SKILL.md index bb5a47a..334b2fb 100644 --- a/.opencode/skills/issue/SKILL.md +++ b/.opencode/skills/issue/SKILL.md @@ -21,39 +21,27 @@ Issue должно содержать всё необходимое, чтобы ```markdown ## Контекст -(зачем это нужно, какая проблема решается) +Зачем: [мотивация — почему это нужно] +Контекст: [текущее состояние, что есть сейчас] -## Что сделать -(пошагово, с путями к файлам) +## Задача +[Что делаем — пошагово, с путями к файлам и номерами строк] -### Шаг 1: ... -- Файл: `path/to/file.py` -- Изменить: ... +## Контракты +[Ожидаемое поведение: API, форматы запросов/ответов, коды ошибок] -### Шаг 2: ... +## Инварианты +[Правила без исключений: лимиты, ограничения, выбранные технологии] -## Проверка -(команды и ожидаемый результат) -- `pytest tests/test_xxx.py -x -q --no-cov` → all passed -- `ruff check path/to/file.py` → All checks passed -- `mypy path/to/file.py` → no issues +## Граничные случаи +[Что при ошибках: невалидный вход, отказ внешнего сервиса, превышение лимита] -## Acceptance criteria -(явный чек-лист — что должно быть верно в результате, не команды проверки) -- [ ] Эффект A работает в случае B -- [ ] Файл C не содержит паттерн D -- [ ] Тест E покрывает ветку F -- [ ] Coverage ≥ 80% на изменённых файлах +## Вне scope +[Что НЕ делаем в этой итерации] -## Dependencies -(связи с другими issue/PR — блокировки и порядок) -- Blocked by #N (этот PR нельзя начать пока #N не смержен) -- Do not merge until #N merges (этот PR готов, но ждёт #N) -- Part of #N (подзадача родительского issue) - -## Связанные ресурсы -- Ref #33 -- [PR #34](https://github.com/...) +## Критерии приемки +- [ ] Проверяемый сценарий 1: "пользователь делает X → видит Y" +- [ ] Проверяемый сценарий 2 ``` ## Правило дробления @@ -79,8 +67,8 @@ Issue создаёт **subagent** (general type), а не основной аг **Subagent (полная ответственность):** 1. Загрузи навык `issue` 2. Собери контекст — прочитай файлы из intent summary, пойми задачу, оцени объём (правило дробления ниже) -3. Составь self-contained body по шаблону (Контекст → Что сделать → Проверка → Acceptance criteria → Dependencies → Связанные ресурсы) -4. Запусти `create-issue({ title: "...", body: "...", labels: ["..."] })` tool (НЕ raw `gh issue create` — заблокирован deny; tool валидирует conventional title format и headings `## Контекст`/`## Задача`/`## Критерии приемки`) +3. Составь self-contained body по шаблону (Контекст → Задача → Контракты → Инварианты → Граничные случаи → Вне scope → Критерии приемки) +4. Запусти `create-issue({ title: "...", body: "...", labels: ["..."] })` tool (НЕ raw `gh issue create` — заблокирован deny; tool валидирует conventional title format и headings `## Контекст`/`## Задача`/`## Контракты`/`## Инварианты`/`## Граничные случаи`/`## Вне scope`/`## Критерии приемки`) 5. Верни URL созданного issue основному агенту Main agent НЕ пишет body и НЕ запускает `create-issue` — всё через subagent. Это согласовано с `run-pipeline` skill (Phase 0: "через subagent с `issue` skill") и `AGENTS.md` (Dev Workflow, step 2: "delegate to `task` subagent"). @@ -89,27 +77,40 @@ Main agent НЕ пишет body и НЕ запускает `create-issue` — в ```markdown ## Контекст -Zoom breathing падает при включённом geometry crop — crop использует probe.width вместо iw. +Зачем: API эндпоинт /api/videos/analyze отвечает 2-5 секунд из-за повторного обращения к Claude API для тех же видео. Кеширование результата сократит время ответа до <100мс для повторных запросов. +Контекст: сейчас AnalysisService обращается к Claude API при каждом вызове, кеша нет. -## Что сделать -### Шаг 1: Заменить probe dimensions на iw/ih выражения -- Файл: `src/video_uniq/effects/camera.py:72` -- Заменить `w, h = probe.width, probe.height` на `iw`/`ih` выражения +## Задача +1. В `services/analysis_service.py:45` — добавить проверку кеша перед вызовом Claude API +2. В `utils/cache.py` — использовать RedisCache (уже есть в проекте) +3. TTL результата анализа — 30 дней +4. При cache hit — пропустить обращение к TranscriptService и AnalysisService -## Проверка -- `pytest tests/test_effects.py -x -q --no-cov` → all passed -- `pytest tests/test_new_effects_real.py::test_geometry_crop_with_zoom_breathing_real` → passed +## Контракты +- POST /api/videos/analyze — без изменений в API +- При cache hit: 200 OK, время ответа <100мс +- При cache miss: 200 OK, время ответа 2-5 сек (как сейчас) -## Acceptance criteria -- [ ] Geometry crop использует `iw`/`ih`, не `probe.width`/`probe.height` -- [ ] Zoom breathing не падает при включённом geometry crop -- [ ] Регрессионный тест покрывает комбинацию zoom breathing + geometry crop +## Инварианты +- Кеш только через Redis (RedisCache из utils/cache.py) +- TTL результата анализа — 30 дней (2592000 сек) +- Невалидный ответ Claude НЕ кешируется -## Dependencies -- Closes #33 +## Граничные случаи +- Redis недоступен → логировать warning, продолжить без кеша (cache miss) +- Кеш содержит устаревший формат → invalidate, пересчитать +- Конкурентные запросы на одно видео → первый пишет в кеш, последующие берут из кеша -## Связанные ресурсы -- Closes #33 +## Вне scope +- ❌ Кеширование субтитров (отдельная задача) +- ❌ Инвалидация по времени просмотра видео +- ❌ Админ-панель для управления кешем + +## Критерии приемки +- [ ] Повторный анализ того же видео → результат мгновенно (<100мс) +- [ ] Новое видео → результат через 2-5 сек (как раньше) +- [ ] Redis недоступен → API работает (без кеша), в логах warning +- [ ] pytest tests/test_analysis_service.py проходит ``` ## Пример плохого issue @@ -130,8 +131,9 @@ create-issue({ title: "type(scope): description", body: "...", labels: ["