docs: канон поднят с версии 7 до 12
- каталог задач переехал в tasks/ в корне, спринт упразднён — приоритет теперь порядок строк в BACKLOG.md, четыре задачи набора вернулись в беклог - гейт: путь docs.py переведён на av-dev-docs вместо снесённого av-dev-pm, добавлены шаги tasks.py check и openspec.py check - относительные ссылки внутри задач и ссылки из docs/ на задачи починены
This commit is contained in:
@@ -117,7 +117,7 @@ Go 1.26, один статический бинарь (`CGO_ENABLED=0`). Module
|
||||
- Ничего не гоняется против **живого** qBittorrent, LLM и метабаз:
|
||||
интеграционные тесты за env-гейтами, запускает человек вручную.
|
||||
- Качество распознавания гейтом не проверяется вовсе и проверяться не будет:
|
||||
размеченный корпус решено не собирать (`docs/tasks/REJECTED.md`,
|
||||
размеченный корпус решено не собирать (`tasks/REJECTED.md`,
|
||||
2026-08-06). Сдвиг точности виден только по рабочему потоку.
|
||||
|
||||
## Запреты
|
||||
@@ -149,9 +149,14 @@ Go 1.26, один статический бинарь (`CGO_ENABLED=0`). Module
|
||||
исключения инварианта выше); снятие последней копии
|
||||
данных; правка уже применённой миграции; `git push --force`; удаление или
|
||||
перезапись файла в библиотеке Jellyfin, которого мы не создавали.
|
||||
- **Общий станок** — покрасневший `task gate` на `master` врывается в
|
||||
замороженный спринт: пока он красный, ни одна задача не считается сделанной.
|
||||
- **Ориентир по размеру спринта:** 5–8 задач. Ориентир, а не закон.
|
||||
- **Что считается сломанным:** покрасневший `task gate` на `master`. Пока он
|
||||
красный, ни одна задача не считается сделанной, и чинится он вперёд любой
|
||||
задачи — станок общий.
|
||||
- **Приоритет — это порядок строк в [tasks/BACKLOG.md](tasks/BACKLOG.md).**
|
||||
Первая строка секции — то, что делают следующим. Порядок назначает человек на
|
||||
груминге (`av-dev-tasks:groom`), машина его не выводит.
|
||||
- **Ориентир по размеру порции разбора на груминге:** 5–8 задач. Ориентир, а не
|
||||
закон.
|
||||
- **Что такое «сделана»:** пайплайн задачи пройден целиком (спека → код → оба
|
||||
чекпоинта ревью → archive) и критерии приёмки проверены поимённо.
|
||||
|
||||
@@ -201,12 +206,12 @@ Go 1.26, один статический бинарь (`CGO_ENABLED=0`). Module
|
||||
- [docs/research/](docs/research/README.md) — наблюдения за чужими форматами.
|
||||
- [docs/adr/](docs/adr/README.md) — журнал решений, неизменяемый.
|
||||
- [docs/review.md](docs/review.md) — настройка конвейера ревью и журнал дефектов.
|
||||
- [docs/tasks/](docs/tasks/BACKLOG.md) — задачи и цели: одна запись = один файл
|
||||
в `items/` + строка в индексе. Ведётся скиллом `av-dev-pm:tasks`, ритуал
|
||||
спринта — `av-dev-pm:session`.
|
||||
- [tasks/](tasks/BACKLOG.md) — задачи и цели: одна запись = один файл
|
||||
в `items/` + строка в индексе, порядок строк = приоритет. Ведётся скиллом
|
||||
`av-dev-tasks:tasks`, разбор беклога — `av-dev-tasks:groom`.
|
||||
|
||||
**Tududi** (проект `jellybit`, project_id 14) — только инбокс сырых идей. Идея
|
||||
становится задачей, когда её оформляют файлом в `docs/tasks/items/`.
|
||||
становится задачей, когда её оформляют файлом в `tasks/items/`.
|
||||
|
||||
## Конвенции кода
|
||||
|
||||
|
||||
@@ -42,7 +42,7 @@ TMDB/TVDB/TVMaze) → раскладка в библиотеку хардлин
|
||||
REST API, веб-UI, Telegram-бот и CLI (`jellybit add`).
|
||||
|
||||
Из источников поддержаны magnet и `.torrent`-файл; фетч `.torrent` по обычной
|
||||
ссылке — в планах. Что дальше — [docs/tasks/ROADMAP.md](docs/tasks/ROADMAP.md).
|
||||
ссылке — в планах. Что дальше — [tasks/ROADMAP.md](tasks/ROADMAP.md).
|
||||
|
||||
## Документация
|
||||
|
||||
@@ -64,7 +64,7 @@ REST API, веб-UI, Telegram-бот и CLI (`jellybit add`).
|
||||
[веб-UI](docs/conventions/web-ui.md).
|
||||
- [docs/adr/](docs/adr/README.md) — журнал решений (почему так), неизменяемый.
|
||||
- [docs/research/](docs/research/README.md) — наблюдения за чужими форматами.
|
||||
- [docs/tasks/](docs/tasks/BACKLOG.md) — задачи и цели.
|
||||
- [tasks/](tasks/BACKLOG.md) — задачи и цели.
|
||||
|
||||
Раскладка документации задана каноном av-dev и проверяется шагом `canon` в
|
||||
`task gate`.
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
{
|
||||
"canon": 7,
|
||||
"canon": 12,
|
||||
"migrations": "internal/store/migrations"
|
||||
}
|
||||
|
||||
@@ -53,7 +53,7 @@
|
||||
|
||||
- Критерий приёмки задачи «запрос поиска содержит параметр языка» выполнен быть
|
||||
не может и отменён этим решением. Расхождение вынесено вопросом человеку —
|
||||
разведка [tvdb-search-response-live-check](../tasks/items/tvdb-search-response-live-check.md).
|
||||
разведка [tvdb-search-response-live-check](../../tasks/items/tvdb-search-response-live-check.md).
|
||||
- **Решение опирается на документацию, а не на замер.** Семантика параметра и
|
||||
форма блока переводов живым API не подтверждены —
|
||||
[research/tvdb-search-translations.md](../research/tvdb-search-translations.md).
|
||||
|
||||
@@ -172,7 +172,7 @@ Jellyfin указывают на `movies`/`series`, а не на корень
|
||||
|
||||
Места, где устройство знаемо тонкое: не дефекты, а принятые пока пробелы. Здесь
|
||||
только адрес и одна фраза — что именно не сделано; работа под каждым живёт
|
||||
задачей в [tasks/BACKLOG.md](tasks/BACKLOG.md). Список нужен ревью: правка,
|
||||
задачей в [tasks/BACKLOG.md](../tasks/BACKLOG.md). Список нужен ревью: правка,
|
||||
попавшая в такую область, стоит дороже, чем выглядит.
|
||||
|
||||
| Область | Чего нет сегодня | Задача |
|
||||
|
||||
+1
-1
@@ -1,7 +1,7 @@
|
||||
# Паспорт проекта
|
||||
|
||||
Зачем это и для кого. [architecture.md](architecture.md) отвечает «как
|
||||
устроено», [tasks/ROADMAP.md](tasks/ROADMAP.md) — «что уже умеет», паспорт —
|
||||
устроено», [tasks/ROADMAP.md](../tasks/ROADMAP.md) — «что уже умеет», паспорт —
|
||||
«зачем и для кого».
|
||||
|
||||
## Цель
|
||||
|
||||
+2
-2
@@ -252,8 +252,8 @@ Go-сервиса и что здесь уже проскакивало. Устр
|
||||
**Ориентир частоты.** `medium` закрывает большинство задач, `large` рассчитана
|
||||
на 5–10% и приходится на крупную функциональность, а не на уборку: задача типа
|
||||
`chore` или `fix`, собранная из нитей прошлого ревью, идёт в `small` или
|
||||
`medium`, даже когда трогает файл из перечней выше. `large` чаще одной задачи на
|
||||
спринт означает ошибку в критерии, а не спринт из сложных задач.
|
||||
`medium`, даже когда трогает файл из перечней выше. `large` чаще одной задачи из
|
||||
десяти означает ошибку в критерии, а не полосу сложных задач подряд.
|
||||
|
||||
### Недоступно проверке
|
||||
|
||||
|
||||
@@ -1,14 +0,0 @@
|
||||
# Спринт
|
||||
|
||||
- **Цель:** [🎯 Раздача узнаётся верно без подсказок человека](items/recognition-accuracy.md)
|
||||
- **Начат:** 2026-08-06
|
||||
- **Спринт:** `2026-08-06`
|
||||
|
||||
Урожай спринта поднимается `tasks.py list --tag sprint:2026-08-06` — это первая порция переоценки на сессии.
|
||||
|
||||
## Набор
|
||||
|
||||
- [✨ Узаконить confidence-гейт авто-раскладки в спеке и сделать его выключаемым (дефолт 0.7)](items/auto-link-confidence-gate.md) — Решено (B): гейт оставляем как доп. проверку на ревью — выключаемый порог, дефолт 0.85→0.7, записать в спеку
|
||||
- [🐞 Тормозить опрос qBittorrent бэкоффом при недоступности и эскалировать устойчивый сбой](items/background-error-noise.md) — недоступный qBittorrent опрашивается каждые 5 с и даёт WARN на каждом тике: нужен экспоненциальный бэкофф до минутного потолка со сбросом по первому успеху и ERROR на устойчивой деградации
|
||||
- [🐞 Санитизировать название из метабазы перед подстановкой в план](items/metadata-title-sanitize.md) — plan.Title = match.Title подставляется ПОСЛЕ sanitizePlan — название из TMDB/TVDB уезжает в имя каталога Jellyfin дословно, с невидимыми символами и гомоглифами, и авто-раскладка это пропускает
|
||||
- [🐞 Отправлять на ревью раздачу с непомещающимся именем вместо отказа](items/long-title-to-review.md) — название длиннее ~237 байт роняет раскладку в failed с текстом системной ошибки: пользователь видит «file name too long» вместо карточки ревью, где это чинится подсказкой
|
||||
+64
-26
@@ -26,16 +26,20 @@ from pathlib import Path
|
||||
|
||||
OUT_DIR = Path("tmp/gate")
|
||||
|
||||
# docs.py скилла av-dev-pm:canon — проверка раскладки docs/ против канона.
|
||||
# Скрипты трёх плагинов av-dev. Каждый проверяет своё и ни один не тянет
|
||||
# остальных: без своего шага дрейф соответствующего каталога перестаёт ловиться
|
||||
# молча.
|
||||
# docs.py — раскладка docs/ против канона (av-dev-docs:canon)
|
||||
# tasks.py — согласованность индексов каталога задач (av-dev-tasks:tasks)
|
||||
# openspec.py — форма openspec/config.yaml (av-dev-code:openspec)
|
||||
# Путь берётся из каталога маркетплейса (он без хеша версии, в отличие от
|
||||
# cache/), переопределяется переменной DOCS_PY: переустановка плагина не должна
|
||||
# cache/), переопределяется переменной: переустановка плагина не должна
|
||||
# требовать правки гейта. Если скрипта нет — шаг краснеет, а не пропускается:
|
||||
# молча пропущенная проверка даёт ложное ощущение проверенности.
|
||||
DOCS_PY_DEFAULT = (
|
||||
Path.home()
|
||||
/ ".claude/plugins/marketplaces/av-dev-skills"
|
||||
/ "av-dev-pm/skills/canon/scripts/docs.py"
|
||||
)
|
||||
MARKETPLACE = Path.home() / ".claude/plugins/marketplaces/av-dev-skills"
|
||||
DOCS_PY_DEFAULT = MARKETPLACE / "av-dev-docs/skills/canon/scripts/docs.py"
|
||||
TASKS_PY_DEFAULT = MARKETPLACE / "av-dev-tasks/skills/tasks/scripts/tasks.py"
|
||||
OPENSPEC_PY_DEFAULT = MARKETPLACE / "av-dev-code/skills/openspec/scripts/openspec.py"
|
||||
|
||||
OK, FAIL, WARN, SKIP = "OK", "FAIL", "WARN", "SKIP"
|
||||
|
||||
@@ -92,6 +96,34 @@ def step(name: str, cmd: list[str], hint: str = "", env: dict[str, str] | None =
|
||||
return ok
|
||||
|
||||
|
||||
def plugin_step(
|
||||
name: str, var: str, default: Path, plugin: str, args: list[str], hint: str
|
||||
) -> None:
|
||||
"""Шаг, который гоняет скрипт плагина av-dev.
|
||||
|
||||
Отсутствие скрипта краснеет, а не пропускается: молча пропущенная проверка
|
||||
неотличима от пройденной. Коды выхода у всех трёх скриптов общие: 0 сошлось,
|
||||
1 дрейф, 2 ошибка употребления, 3 окружение, 4 внутренний сбой. Различать 1
|
||||
и остальные обязательно — дрейф чинится правкой проекта, прочее нет.
|
||||
"""
|
||||
script = Path(os.environ.get(var) or default)
|
||||
if not script.is_file():
|
||||
record(FAIL, name, f"{script.name} не найден: {script} — переустанови"
|
||||
f" плагин {plugin} или задай путь переменной {var}")
|
||||
return
|
||||
log = OUT_DIR / f"{name}.log"
|
||||
proc = subprocess.run(
|
||||
["python3", str(script), *args], capture_output=True, text=True,
|
||||
)
|
||||
log.write_text(proc.stdout + proc.stderr, encoding="utf-8")
|
||||
if proc.returncode == 0:
|
||||
record(OK, name)
|
||||
elif proc.returncode == 1:
|
||||
record(FAIL, name, f"{hint} → {log}")
|
||||
else:
|
||||
record(FAIL, name, f"{script.name} не отработал (код {proc.returncode}) → {log}")
|
||||
|
||||
|
||||
def main() -> int:
|
||||
OUT_DIR.mkdir(parents=True, exist_ok=True)
|
||||
base = base_rev(sys.argv)
|
||||
@@ -186,25 +218,31 @@ def main() -> int:
|
||||
# нетронутые плейсхолдеры и две сверки с кодом — включая «миграция изменена,
|
||||
# а database.md нет» (отдельного шага er-schema поэтому больше нет).
|
||||
# База диффа обязательна: без неё сверка миграций со схемой не гоняется.
|
||||
docs_py = Path(os.environ.get("DOCS_PY") or DOCS_PY_DEFAULT)
|
||||
if not docs_py.is_file():
|
||||
record(FAIL, "canon", f"docs.py не найден: {docs_py} — переустанови плагин"
|
||||
" av-dev-pm или задай путь переменной DOCS_PY")
|
||||
else:
|
||||
log = OUT_DIR / "canon.log"
|
||||
proc = subprocess.run(
|
||||
["python3", str(docs_py), "check", "--dir", ".", "--base", base],
|
||||
capture_output=True, text=True,
|
||||
)
|
||||
log.write_text(proc.stdout + proc.stderr, encoding="utf-8")
|
||||
if proc.returncode == 0:
|
||||
record(OK, "canon")
|
||||
elif proc.returncode == 1:
|
||||
record(FAIL, "canon", f"раскладка docs/ разошлась с каноном → {log}")
|
||||
else:
|
||||
# 2 — ошибка употребления, 3 — окружение, 4 — внутренний сбой.
|
||||
# Это не дрейф документации, и чинится оно не правкой docs/.
|
||||
record(FAIL, "canon", f"docs.py не отработал (код {proc.returncode}) → {log}")
|
||||
plugin_step(
|
||||
"canon", "DOCS_PY", DOCS_PY_DEFAULT, "av-dev-docs",
|
||||
["check", "--dir", ".", "--base", base],
|
||||
"раскладка docs/ разошлась с каноном",
|
||||
)
|
||||
|
||||
# --- Каталог задач ---
|
||||
# Согласованность индексов с файлами items/: бездомная запись, строка без
|
||||
# файла, порядок секций роадмапа, сырьё не в конце секции. docs.py этого не
|
||||
# смотрит — каталог принадлежит другому плагину.
|
||||
plugin_step(
|
||||
"tasks", "TASKS_PY", TASKS_PY_DEFAULT, "av-dev-tasks",
|
||||
["check", "--dir", "tasks"],
|
||||
"индексы задач разошлись с items/",
|
||||
)
|
||||
|
||||
# --- Форма настройки OpenSpec ---
|
||||
# Незаменённый пример в openspec/config.yaml читается как настроенный файл,
|
||||
# а работает как пустой. Ловит это только свой шаг: docs.py про config.yaml
|
||||
# молчит с канона 10.
|
||||
plugin_step(
|
||||
"openspec", "OPENSPEC_PY", OPENSPEC_PY_DEFAULT, "av-dev-code",
|
||||
["check", "--dir", "."],
|
||||
"openspec/config.yaml разошёлся с канонической формой",
|
||||
)
|
||||
|
||||
# --- Секреты ---
|
||||
# Гоняем всегда: секрет утекает из любого файла, не только из кода.
|
||||
|
||||
@@ -25,6 +25,9 @@
|
||||
- [✨ Править на ревью маппинг «файл → серия» и раскладывать вручную при провале LLM](items/review-mapping-editor.md) — правка S·E, «нумеровать подряд» и ручной режим при полном провале LLM были запланированы объёмом Ф5 и не заведены задачей — в ревью сегодня можно только подсказать текстом
|
||||
- [✨ Заказать спекой крайние случаи именования: многофайловый фильм, редакции, двойная серия](items/naming-edge-cases.md) — стэкинг частей (part1/cd1), редакции [edition-…] и двойная серия SxxEyy-Eyy описаны нарративом, но в file-layout не заказаны — раскладка таких раздач не определена
|
||||
- [🔬 Форма ответа поиска TheTVDB и семантика параметра language](items/tvdb-search-response-live-check.md) — форма ответа поиска TheTVDB принята по swagger 4.7.10 и живым прогоном не подтверждена — при иной форме разбор молча уходит в фолбэк, гейт зелёный, локализованное название не работает
|
||||
- [✨ Узаконить confidence-гейт авто-раскладки в спеке и сделать его выключаемым (дефолт 0.7)](items/auto-link-confidence-gate.md) — Решено (B): гейт оставляем как доп. проверку на ревью — выключаемый порог, дефолт 0.85→0.7, записать в спеку
|
||||
- [🐞 Отправлять на ревью раздачу с непомещающимся именем вместо отказа](items/long-title-to-review.md) — название длиннее ~237 байт роняет раскладку в failed с текстом системной ошибки: пользователь видит «file name too long» вместо карточки ревью, где это чинится подсказкой
|
||||
- [🐞 Санитизировать название из метабазы перед подстановкой в план](items/metadata-title-sanitize.md) — plan.Title = match.Title подставляется ПОСЛЕ sanitizePlan — название из TMDB/TVDB уезжает в имя каталога Jellyfin дословно, с невидимыми символами и гомоглифами, и авто-раскладка это пропускает
|
||||
- [🔬 Канон нумерации серий и порядок у провайдера тега](items/episode-numbering-canon.md) — Косметика/редкость: порядок просмотра ок, но у тайтлов со спорным порядком (Бибоп) Jellyfin подтягивает не те подписи серий, если канон файлов ≠ дефолтный порядок провайдера тега
|
||||
- [🔬 Тексты и формат уведомлений в Telegram](items/telegram-messages-audit.md) — зонтичный проход по всем текстам бота: полнота карточек, единый язык, оформление; порождает под-задачи
|
||||
- [🔬 guessit как сервис-спутник](items/guessit-sidecar.md) — go-ptn слабее питоновского guessit — если точности пред-парса не хватит, завернуть guessit в сервис-спутник рядом с бинарём
|
||||
@@ -43,6 +46,7 @@
|
||||
- [✨ Чистить БД от терминальных задач и сырых ответов LLM старше срока хранения](items/db-retention-cleanup.md) — терминальные задачи и сырые ответы LLM копятся вечно — без авточистки список загрузок и БД деградируют по мере эксплуатации
|
||||
- [🧹 Свести термины домена в словарь единого языка](items/ubiquitous-language-glossary.md) — наименования домена расходятся между спеками, UI и кодом — нет единого глоссария (на нём же стоит агент-ревьювер наименований)
|
||||
- [🧹 Разобрать кандидатов по тестам и записать конвенцию](items/tests-convention.md) — как пишем тесты, не записано нигде: пункт «Тесты» в convention-candidates не пересматривали, он обещает фикстуры в testdata/, которых в проекте нет — а трение накопилось (четыре внешних клиента, fakeStore с инъекцией ошибок, env-гейты, флаки-прогон, diff-coverage)
|
||||
- [🐞 Тормозить опрос qBittorrent бэкоффом при недоступности и эскалировать устойчивый сбой](items/background-error-noise.md) — недоступный qBittorrent опрашивается каждые 5 с и даёт WARN на каждом тике: нужен экспоненциальный бэкофф до минутного потолка со сбросом по первому успеху и ERROR на устойчивой деградации
|
||||
- [🔬 Потолок нагрузки: 100 одновременных загрузок, план-максимум 1000](items/scale-100-downloads.md) — Зафиксировать в НФТ ориентир 100/1000 загрузок + аудит узких мест (SQLite, воркер, поллинг)
|
||||
- [🔬 Завершение загрузки через webhook](items/completion-webhook.md) — завершение сейчас ловим поллингом qBittorrent — webhook реагировал бы быстрее, но связывает нас с его конфигом (решим по опыту эксплуатации)
|
||||
- [🔬 Кандидаты в конвенции кода](items/convention-candidates.md) — накоплен список кандидатов (внешние клиенты, конкурентность, тесты, CLI, время) — надо решить, что из них стало реальным трением, а что выдумано вперёд
|
||||
+1
-1
@@ -37,7 +37,7 @@
|
||||
согласованность, но `confidence` ниже порога → review.
|
||||
4. **Конфиг-конвенция/дока:** описать ключ в `docs/conventions/config.md` (диапазон
|
||||
[0,1], 0 = выкл, дефолт 0.7) и поправить значение в таблице «Настройки с
|
||||
числовым значением» [docs/database.md](../../database.md) — дом числа там, и
|
||||
числовым значением» [docs/database.md](../../docs/database.md) — дом числа там, и
|
||||
при смене дефолта оно разъедется первым. Формулировки инварианта в
|
||||
`CLAUDE.md` и ложноположительного в `docs/review.md` уже приведены к
|
||||
«единственным гейтом не является» (канон 4, 2026-08-06) — переписывать их
|
||||
@@ -48,7 +48,7 @@
|
||||
пункт, вероятно, закрыт и подлежит вычёркиванию.
|
||||
- **Язык вывода связан с мапперами.** Провенанс — ревью `tvdb-title-locale`
|
||||
(2026-08-07,
|
||||
[отчёт триажа](../../../openspec/changes/archive/2026-08-07-tvdb-title-locale/review/report.md),
|
||||
[отчёт триажа](../../openspec/changes/archive/2026-08-07-tvdb-title-locale/review/report.md),
|
||||
находка R2 прохода `architecture`). Язык вывода живёт в пяти местах четырёх
|
||||
пакетов, и теста, связывающего множество кодов языка с мапперами, нет:
|
||||
забытая ветка молча даст английский вывод вместо ошибки. Кандидат в правило
|
||||
@@ -3,7 +3,6 @@
|
||||
- **Тип:** fix
|
||||
- **Категория:** Ядро продукта
|
||||
- **Зачем:** название длиннее ~237 байт роняет раскладку в failed с текстом системной ошибки: пользователь видит «file name too long» вместо карточки ревью, где это чинится подсказкой
|
||||
- **Теги:** sprint:2026-08-06
|
||||
|
||||
Длина компонента пути ограничена файловой системой (255 байт на имя, минус
|
||||
расширение и суффиксы — практический потолок около 237). Название такой длины
|
||||
@@ -20,7 +19,7 @@
|
||||
есть и его надо переиспользовать, а не изобретать.
|
||||
|
||||
Провенанс: ревью изменения `tvdb-title-locale`, находка AD4 —
|
||||
[отчёт триажа](../../../openspec/changes/archive/2026-08-07-tvdb-title-locale/review/report.md).
|
||||
[отчёт триажа](../../openspec/changes/archive/2026-08-07-tvdb-title-locale/review/report.md).
|
||||
Понижена там не по доказательности, а по принадлежности к диффу: путь этим
|
||||
изменением не тронут.
|
||||
|
||||
@@ -59,7 +58,7 @@ n=250 → Apply err=… file name too long, results=0
|
||||
**Оракул:** тот же тест — проверяет, что каталог цели пуст.
|
||||
- Причина, показанная человеку, не содержит текста системной ошибки. **Оракул:**
|
||||
утверждение теста на текст причины плюс конвенция
|
||||
[errors.md](../../conventions/errors.md) — перевод доменной ошибки на внешней
|
||||
[errors.md](../../docs/conventions/errors.md) — перевод доменной ошибки на внешней
|
||||
границе.
|
||||
- Проверка длины стоит **до** первой операции с файловой системой. **Оракул:**
|
||||
чтение диффа на ревью; тест на пустоту каталога цели его подтверждает.
|
||||
+1
-2
@@ -3,7 +3,6 @@
|
||||
- **Тип:** fix
|
||||
- **Категория:** Ядро продукта
|
||||
- **Зачем:** plan.Title = match.Title подставляется ПОСЛЕ sanitizePlan — название из TMDB/TVDB уезжает в имя каталога Jellyfin дословно, с невидимыми символами и гомоглифами, и авто-раскладка это пропускает
|
||||
- **Теги:** sprint:2026-08-06
|
||||
|
||||
Название, пришедшее из метабазы, подставляется в план **после** того, как план
|
||||
прошёл санитизацию: `plan.Title = match.Title` стоит ниже `sanitizePlan`.
|
||||
@@ -22,7 +21,7 @@
|
||||
а не `critical`.
|
||||
|
||||
Провенанс: ревью изменения `tvdb-title-locale`, находка 2 —
|
||||
[отчёт триажа](../../../openspec/changes/archive/2026-08-07-tvdb-title-locale/review/report.md).
|
||||
[отчёт триажа](../../openspec/changes/archive/2026-08-07-tvdb-title-locale/review/report.md).
|
||||
|
||||
## Воспроизведение
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
- **Теги:** goal:complex-releases
|
||||
|
||||
Целевые имена для типового фильма и типового сезона заказаны
|
||||
[file-layout](../../../openspec/specs/file-layout/spec.md). Крайние случаи там
|
||||
[file-layout](../../openspec/specs/file-layout/spec.md). Крайние случаи там
|
||||
не заказаны: до перевода на канон они жили разделом «Крайние случаи» нарратива
|
||||
`docs/specs/jellyfin-layout.md` (удалён, текст в истории git) как намерение, а
|
||||
не как требование. Значит, что делает код в этих случаях, без чтения кода
|
||||
@@ -24,7 +24,7 @@
|
||||
- **Двойная серия в одном файле** — `… SxxEyy-Eyy`.
|
||||
- **Спецвыпуски** — `Season 00`. Сперва проверить, не покрыты ли уже
|
||||
требованием «Роли файлов на краях раздачи» в
|
||||
[recognition](../../../openspec/specs/recognition/spec.md).
|
||||
[recognition](../../openspec/specs/recognition/spec.md).
|
||||
|
||||
## Критерии приёмки
|
||||
|
||||
@@ -21,7 +21,7 @@ OpenSpec в сторону воспроизводимых автопроверо
|
||||
профили `quick`/`standard`/`deep`/`design`, контракт находок, границы покрытия,
|
||||
храповик «находка → конвенция → правило → удаление», журнал проскочивших
|
||||
дефектов и процедура калибровки. Подробности — ADR
|
||||
[ADR-2026-07-23-review-pipeline-generative](../../adr/ADR-2026-07-23-review-pipeline-generative.md).
|
||||
[ADR-2026-07-23-review-pipeline-generative](../../docs/adr/ADR-2026-07-23-review-pipeline-generative.md).
|
||||
|
||||
Открытый вопрос «дробить ли проход по конвенциям на узкие оптики» закрыт:
|
||||
**не дробим** — декорреляция внимания без декорреляции суждения почти не
|
||||
@@ -32,14 +32,14 @@ OpenSpec в сторону воспроизводимых автопроверо
|
||||
Проектные копии агентов (`.claude/agents/jellybit-review-*`) и скиллов
|
||||
(`review-pipeline`, `task-pipeline`, `task-batch`) удалены в пользу плагина
|
||||
`av-dev-pipeline`. Проектная специфика теперь приходит из документов канона —
|
||||
[docs/review.md](../../review.md): типовые узлы, ложноположительные, вопросы по
|
||||
[docs/review.md](../../docs/review.md): типовые узлы, ложноположительные, вопросы по
|
||||
темам, триггеры метки, недоступное проверке.
|
||||
|
||||
Два прохода плагин при этом **упразднил**, и это надо помнить:
|
||||
|
||||
- `idiom` — поимённая сверка со стайлгайдами языка не задаётся теперь ни одним
|
||||
проходом; куда переселены способные части и почему класс признан обратимым —
|
||||
[docs/review.md](../../review.md) → «Перестали проверять сознательно».
|
||||
[docs/review.md](../../docs/review.md) → «Перестали проверять сознательно».
|
||||
- `negative` — вопрос «что опытный человек отсюда удалил бы» вошёл в
|
||||
`architecture` вторым обязательным.
|
||||
|
||||
@@ -58,10 +58,10 @@ OpenSpec в сторону воспроизводимых автопроверо
|
||||
больше нет» неотличимо от «больше не поместилось» — то есть ровно тот сигнал,
|
||||
ради которого потолок и заведён. Первый замер калибровки стоит начать с этого:
|
||||
дефект прогона виден без инъекции.
|
||||
- **Заполнить журнал дефектов** в [docs/review.md](../../review.md) случаями,
|
||||
- **Заполнить журнал дефектов** в [docs/review.md](../../docs/review.md) случаями,
|
||||
которые уже проскочили ревью, — они станут первыми пробами калибровки.
|
||||
- **Решить судьбу упразднённых проходов:** нужен ли проекту свой `idiom` поверх
|
||||
плагина, или записи в «Недоступно проверке» достаточно.
|
||||
|
||||
Связано: CLAUDE.md (ревью-процесс, конвенции),
|
||||
[docs/conventions/](../../conventions/README.md), «Словарь единого языка».
|
||||
[docs/conventions/](../../docs/conventions/README.md), «Словарь единого языка».
|
||||
@@ -22,7 +22,7 @@
|
||||
в вебе, из бота идёт эскалация по deep-link.
|
||||
|
||||
Смежное: превью раскладки и единый список источников совпадения уже есть
|
||||
([review](../../../openspec/specs/review/spec.md)), так что задача про
|
||||
([review](../../openspec/specs/review/spec.md)), так что задача про
|
||||
редактирование плана, а не про его показ.
|
||||
|
||||
## Критерии приёмки
|
||||
+1
-1
@@ -26,4 +26,4 @@
|
||||
Итог аудита — конкретные под-задачи (эта их порождает). Проход дешёвый, при желании
|
||||
приоритет можно поднять.
|
||||
|
||||
Связано: `internal/tgbot`, [review](../../../openspec/specs/review/spec.md).
|
||||
Связано: `internal/tgbot`, [review](../../openspec/specs/review/spec.md).
|
||||
@@ -3,7 +3,6 @@
|
||||
- **Тип:** chore
|
||||
- **Категория:** Инфраструктура
|
||||
- **Зачем:** как пишем тесты, не записано нигде: пункт «Тесты» в convention-candidates не пересматривали, он обещает фикстуры в testdata/, которых в проекте нет — а трение накопилось (четыре внешних клиента, fakeStore с инъекцией ошибок, env-гейты, флаки-прогон, diff-coverage)
|
||||
- **Теги:** sprint:2026-08-06
|
||||
|
||||
В `docs/conventions/` пять записей, и ни одна не про тесты. Знание о том, как
|
||||
они здесь устроены, живёт в головах и в самих файлах: фикстуры чужих форматов
|
||||
@@ -24,7 +23,7 @@
|
||||
то есть «что краснеет», а не «что стоит проверять».
|
||||
|
||||
**Два кандидата пришли из ревью `tvdb-title-locale`** (2026-08-07,
|
||||
[отчёт триажа](../../../openspec/changes/archive/2026-08-07-tvdb-title-locale/review/report.md)
|
||||
[отчёт триажа](../../openspec/changes/archive/2026-08-07-tvdb-title-locale/review/report.md)
|
||||
→ «Promote candidates»), оба с провенансом прохода, а не из головы:
|
||||
|
||||
- **один стенд чужого API на пакет.** В `tvdb_test.go` завелись два фейка одного
|
||||
@@ -40,7 +39,7 @@
|
||||
- `docs/conventions/tests.md` — новый файл записи конвенции;
|
||||
- `docs/conventions/README.md` — строка в индексе «Записи» и, возможно, строки в
|
||||
таблице «Механизировано»;
|
||||
- `docs/tasks/items/convention-candidates.md` — пункт «Тесты» уходит из списка
|
||||
- `tasks/items/convention-candidates.md` — пункт «Тесты» уходит из списка
|
||||
кандидатов;
|
||||
- `.golangci.yml` и `internal/archrules` — только если что-то из решённого
|
||||
выражается правилом, а не прозой.
|
||||
@@ -17,6 +17,6 @@
|
||||
это (magnet / ссылка на .torrent / .torrent-файл / сообщение бота). Сейчас текстовое
|
||||
поле идёт только через `magnet.Parse`.
|
||||
|
||||
Связано: [architecture.md](../../architecture.md) → «Внешние границы и форматы»
|
||||
Связано: [architecture.md](../../docs/architecture.md) → «Внешние границы и форматы»
|
||||
(`source_type = magnet|torrent|url` уже в схеме), пакет `ingest`, архив change
|
||||
`torrent-file-ingest`.
|
||||
+3
-3
@@ -3,14 +3,14 @@
|
||||
- **Тип:** research
|
||||
- **Категория:** Ядро продукта
|
||||
- **Зачем:** форма ответа поиска TheTVDB принята по swagger 4.7.10 и живым прогоном не подтверждена — при иной форме разбор молча уходит в фолбэк, гейт зелёный, локализованное название не работает
|
||||
- **Теги:** goal:recognition-accuracy, sprint:2026-08-06
|
||||
- **Теги:** goal:recognition-accuracy
|
||||
|
||||
Задача `tvdb-title-locale` научила клиент TVDB брать локализованное название из
|
||||
блока переводов ответа `/search` и заполнять `OriginalTitle` primary name'ом. Но
|
||||
живым прогоном форма ответа не сверялась: `CLAUDE.md` → «Запреты» запрещает
|
||||
ходить в боевые метабазы из отладочных прогонов и расходовать лимиты ключа.
|
||||
Форма взята из публичной документации (swagger TheTVDB v4, версия `4.7.10`) и
|
||||
записана в [docs/research/tvdb-search-translations.md](../../research/tvdb-search-translations.md)
|
||||
записана в [docs/research/tvdb-search-translations.md](../../docs/research/tvdb-search-translations.md)
|
||||
как **условие, а не замер**.
|
||||
|
||||
Разведка нужна потому, что ошибка предположения **не наблюдаема**: разбор уйдёт в
|
||||
@@ -27,7 +27,7 @@
|
||||
|
||||
## Куда ляжет ответ
|
||||
|
||||
- [docs/research/tvdb-search-translations.md](../../research/tvdb-search-translations.md):
|
||||
- [docs/research/tvdb-search-translations.md](../../docs/research/tvdb-search-translations.md):
|
||||
предположения заменяются наблюдениями с датой прогона, а строка «живым
|
||||
прогоном не подтверждено» — результатом. Условие пересмотра там уже записано.
|
||||
- Решение по трём развилкам, оставшимся от `tvdb-title-locale`:
|
||||
Reference in New Issue
Block a user