docs: разобран урожай судей после подъёма канона

- перечень команд пользователя убран из architecture.md в спеки review и
  state-reconciliation, где ему дом: обзор успел разойтись с ними в обе стороны
- README перестал дублировать деплой и статус — теперь ссылается на дом
- статус «заведена ли задача под пробел» сведён в один регистр открытых вопросов
- шаги tasks.py и openspec.py названы в перечне «что красит безусловно»
- из спеки download-tracking сняты числа умолчаний: их дом — database.md
This commit is contained in:
av
2026-08-09 19:24:59 +03:00
parent c5d62d76ee
commit 69853a96c9
8 changed files with 37 additions and 36 deletions
+6 -2
View File
@@ -106,8 +106,12 @@ Go 1.26, один статический бинарь (`CGO_ENABLED=0`). Module
- **Что красит безусловно:** сборка, `go vet`, `golangci-lint`, `gofmt`, тесты,
флаки-прогон (второй прогон разошёлся с первым), `-race`, накат миграций с
нуля, `gitleaks`, канон документации (`docs.py check` — раскладка `docs/`,
битые ссылки, «миграция изменена, а `database.md` нет»). Причина одна: у
каждого из них есть объективный оракул, спорить не о чем.
битые ссылки, «миграция изменена, а `database.md` нет»), каталог задач
(`tasks.py check --dir tasks` — согласованность `tasks/BACKLOG.md` и
`tasks/items/`), форма конфига OpenSpec (`openspec.py check` — незаменённый
пример в `openspec/config.yaml`). Причина одна: у каждого из них есть
объективный оракул, спорить не о чем. Каждый из трёх последних краснеет и
когда своего скрипта нет: молча пропущенная проверка неотличима от пройденной.
- **Чего в гейте намеренно нет и кто обязан это гонять:**
- `govulncheck` даёт `WARN`, а не `FAIL`: находка тут — состояние
зависимостей, а не диффа. Разбирает агент ревью по трассам вызовов.
+13 -20
View File
@@ -35,14 +35,10 @@ Arr-стек (prowlarr/radarr/sonarr) плохо ложится на русск
## Статус
Рабочий прототип с полным сквозным путём: приём magnet → загрузка в
qBittorrent → распознавание (LLM + опционально базы метаданных
TMDB/TVDB/TVMaze) → раскладка в библиотеку хардлинками, автоматически при
уверенном результате либо через подтверждение человеком. Транспорты приёма:
REST API, веб-UI, Telegram-бот и CLI (`jellybit add`).
Из источников поддержаны magnet и `.torrent`-файл; фетч `.torrent` по обычной
ссылке — в планах. Что дальше — [tasks/ROADMAP.md](tasks/ROADMAP.md).
Рабочий прототип: сквозной путь приём → загрузка → распознавание → раскладка
работает целиком, автоматически при уверенном результате либо через
подтверждение человеком. Что уже умеет и что дальше —
[tasks/ROADMAP.md](tasks/ROADMAP.md).
## Документация
@@ -73,7 +69,8 @@ REST API, веб-UI, Telegram-бот и CLI (`jellybit add`).
Go (один статический бинарь), SQLite (`modernc.org/sqlite` + `sqlx`,
миграции `goose`), HTTP — `chi` + `html/template` + htmx, конфигурация —
TOML, логи — структурированный JSON (`slog`). Подробнее — в
TOML, логи — структурированный JSON (`slog`). Полный перечень с версиями —
[CLAUDE.md](CLAUDE.md) → «Стек»; как эти компоненты сложены —
[docs/architecture.md](docs/architecture.md).
## Конфигурация
@@ -118,16 +115,12 @@ jellybit recognize <infohash> --dry-run [--context "..."] --config ./config.toml
## Доставка
Рассчитан на домашний медиа-сервер. Артефакты репозитория — статический
бинарь (`task build`) и `Dockerfile` (упаковка в `distroless/static`). Образ
собирается целиком **локально** на control-хосте (`task image`) и едет на
сервер через `docker save`/`load` (роль `app_image` в umbar), поэтому
Go-тулчейн и `docker build` на сервере не нужны. В distroless нет shell/curl,
поэтому HEALTHCHECK зовёт сам бинарь: `jellybit healthcheck` (GET `/healthz`
по порту из конфига, exit 0/1).
Контейнер: `user 1000:1000`, порт `8080` на хост, mount `/srv/media` (единая
песочница для хардлинков) + том `/config` (ro, `config.toml`, восстановим при
деплое) + data-том `/data` (SQLite, бекапить); к qBittorrent — по сети Docker.
Рассчитан на домашний медиа-сервер. Артефакты репозитория — статический бинарь
(`task build`) и `Dockerfile`; образ собирается целиком локально на
control-хосте (`task image`) и едет на сервер через `docker save`/`load`.
Конкретная деплой-обвязка (плейбук, секреты) держится в отдельном приватном
репозитории и в комплект не входит.
Параметры запуска — сеть, пользователь, монтирования, healthcheck, — разделение
ответственности с umbar и единая песочница `/srv/media`:
[docs/architecture.md](docs/architecture.md) → «Деплой».
+1 -1
View File
@@ -11,7 +11,7 @@
Верно одно из трёх:
<!-- копия: adr-когда-заводить из av-dev-pm/skills/canon/references/canon.md -->
<!-- копия: adr-когда-заводить из av-dev-docs/skills/canon/references/canon.md -->
- **дорогой откат** — переделка стоит дороже переписывания одного файла;
- **намеренный отказ** от очевидного подхода;
- **пересмотр прежнего решения** — тогда у старой записи обязателен статус
+4 -2
View File
@@ -48,8 +48,10 @@
| `archrules` | собственный анализатор архитектурных правил (часть гейта) | — |
Транспорты приёма — HTTP API, веб-UI, Telegram и CLI (`jellybit add`) — ведут в
один `ingest`; действия пользователя (apply / refine / reject / defer / undo /
retry / delete / dismiss) идут командами к `worker`.
один `ingest`; действия пользователя идут командами к `worker`. Перечень команд
и их эффекты — нормативно в [review](../openspec/specs/review/spec.md), пути
закрытия и удаления — в
[state-reconciliation](../openspec/specs/state-reconciliation/spec.md).
## Внешние границы и форматы
+2 -1
View File
@@ -214,4 +214,5 @@ erDiagram
| `ingest.MaxTorrentSize` | `8 MiB` | предел размера принимаемого `.torrent`; проверяется **до** разбора, поэтому bencode-аллокации на эту величину не масштабируются (см. [research/torrent-bencode-limits.md](research/torrent-bencode-limits.md)) |
**Ретеншена нет ни у одной таблицы**, лимита на размер тела ответа LLM нет,
кэша метабаз нет — всё три пункта в беклоге.
кэша метабаз нет; состояние по каждому пробелу и заведённые под них задачи —
[architecture.md](architecture.md) → «Открытые вопросы».
+1 -2
View File
@@ -101,8 +101,7 @@ REST API работают **без авторизации** осознанно;
бесконечный ответ LLM — это вопросы устойчивости и ресурсов
([architecture.md](architecture.md) → «Эксплуатация»), а не безопасности.
Отсутствие лимита на размер ответа LLM — известный пробел
([architecture.md](architecture.md) → «Открытые вопросы»); задачей он пока не
заведён.
([architecture.md](architecture.md) → «Открытые вопросы»).
- **Целостность содержимого медиафайлов.** Что в контейнере mkv — не наша забота.
- **Цепочка поставки** — модули Go, базовый образ distroless, плагины тулинга.
- **Приватность запросов к внешним сервисам.** Названия раздач уезжают в LLM и
+3 -3
View File
@@ -10,7 +10,7 @@ qBittorrent и сопоставление его состояний (downloading
## Requirements
### Requirement: Поллинг qBittorrent и сопоставление состояний
Worker SHALL периодически (`worker.poll_interval`, дефолт 5 с) опрашивать
Worker SHALL периодически (`worker.poll_interval`) опрашивать
qBittorrent и сопоставлять его состояния раздачи с состоянием загрузки в БД.
Готовые к раскладке состояния (`uploading`/`stalledUP`/`pausedUP`/`stoppedUP`/
`queuedUP`/`forcedUP`, с учётом различий имён между qBit v4 и v5) SHALL переводить
@@ -39,8 +39,8 @@ API после завершения переноса.
### Requirement: Таймауты-предохранители downloading
Система SHALL переводить `metaDL`/`forcedMetaDL` дольше `magnet_timeout` (дефолт
`24h`, редкий предохранитель) в `failed` (`error_code` `magnet_timeout`), а
Система SHALL переводить `metaDL`/`forcedMetaDL` дольше `magnet_timeout`
(редкий предохранитель) в `failed` (`error_code` `magnet_timeout`), а
`stalledDL` дольше `stuck_after` — в `stuck` (`error_code`
`stalled`). Возраст система SHALL считать от времени добавления в qBittorrent
(`added_on`), а не от создания задачи, чтобы базис переживал retry и усыновление.
+7 -5
View File
@@ -2,12 +2,14 @@
Что **можно взять**. Одна задача = один файл `items/<slug>.md`
+ строка здесь. Целей тут нет — они в [ROADMAP.md](ROADMAP.md): беклог — то, что
берут, роадмап — то, подо что берут. Порядка внутри секции нет: «что делать
дальше» отвечает набор спринта. Ведётся скиллом `tasks`.
берут, роадмап — то, подо что берут. Ведётся скиллом `av-dev-tasks:tasks`.
Секции «блокеры» здесь нет и не заводится: блокерэто состояние
(спринт не может продолжаться ни одной задачей), оно живёт до ответа
человека, а его следы — вопросами в файлах задач.
**Порядок строк внутри секции — это приоритет.** Первая строка секции — то, что
делают следующим. Порядок назначает человек на груминге
(`av-dev-tasks:groom`), машина его не выводит.
Секции «блокеры» здесь нет и не заводится: блокер — это состояние, оно живёт до
ответа человека, а его следы — вопросами в файлах задач.
## Ядро продукта