docs: разобран урожай судей после подъёма канона
- перечень команд пользователя убран из architecture.md в спеки review и state-reconciliation, где ему дом: обзор успел разойтись с ними в обе стороны - README перестал дублировать деплой и статус — теперь ссылается на дом - статус «заведена ли задача под пробел» сведён в один регистр открытых вопросов - шаги tasks.py и openspec.py названы в перечне «что красит безусловно» - из спеки download-tracking сняты числа умолчаний: их дом — database.md
This commit is contained in:
@@ -106,8 +106,12 @@ Go 1.26, один статический бинарь (`CGO_ENABLED=0`). Module
|
|||||||
- **Что красит безусловно:** сборка, `go vet`, `golangci-lint`, `gofmt`, тесты,
|
- **Что красит безусловно:** сборка, `go vet`, `golangci-lint`, `gofmt`, тесты,
|
||||||
флаки-прогон (второй прогон разошёлся с первым), `-race`, накат миграций с
|
флаки-прогон (второй прогон разошёлся с первым), `-race`, накат миграций с
|
||||||
нуля, `gitleaks`, канон документации (`docs.py check` — раскладка `docs/`,
|
нуля, `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`: находка тут — состояние
|
- `govulncheck` даёт `WARN`, а не `FAIL`: находка тут — состояние
|
||||||
зависимостей, а не диффа. Разбирает агент ревью по трассам вызовов.
|
зависимостей, а не диффа. Разбирает агент ревью по трассам вызовов.
|
||||||
|
|||||||
@@ -35,14 +35,10 @@ Arr-стек (prowlarr/radarr/sonarr) плохо ложится на русск
|
|||||||
|
|
||||||
## Статус
|
## Статус
|
||||||
|
|
||||||
Рабочий прототип с полным сквозным путём: приём magnet → загрузка в
|
Рабочий прототип: сквозной путь приём → загрузка → распознавание → раскладка
|
||||||
qBittorrent → распознавание (LLM + опционально базы метаданных
|
работает целиком, автоматически при уверенном результате либо через
|
||||||
TMDB/TVDB/TVMaze) → раскладка в библиотеку хардлинками, автоматически при
|
подтверждение человеком. Что уже умеет и что дальше —
|
||||||
уверенном результате либо через подтверждение человеком. Транспорты приёма:
|
[tasks/ROADMAP.md](tasks/ROADMAP.md).
|
||||||
REST API, веб-UI, Telegram-бот и CLI (`jellybit add`).
|
|
||||||
|
|
||||||
Из источников поддержаны magnet и `.torrent`-файл; фетч `.torrent` по обычной
|
|
||||||
ссылке — в планах. Что дальше — [tasks/ROADMAP.md](tasks/ROADMAP.md).
|
|
||||||
|
|
||||||
## Документация
|
## Документация
|
||||||
|
|
||||||
@@ -73,7 +69,8 @@ REST API, веб-UI, Telegram-бот и CLI (`jellybit add`).
|
|||||||
|
|
||||||
Go (один статический бинарь), SQLite (`modernc.org/sqlite` + `sqlx`,
|
Go (один статический бинарь), SQLite (`modernc.org/sqlite` + `sqlx`,
|
||||||
миграции `goose`), HTTP — `chi` + `html/template` + htmx, конфигурация —
|
миграции `goose`), HTTP — `chi` + `html/template` + htmx, конфигурация —
|
||||||
TOML, логи — структурированный JSON (`slog`). Подробнее — в
|
TOML, логи — структурированный JSON (`slog`). Полный перечень с версиями —
|
||||||
|
[CLAUDE.md](CLAUDE.md) → «Стек»; как эти компоненты сложены —
|
||||||
[docs/architecture.md](docs/architecture.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`). Образ
|
(`task build`) и `Dockerfile`; образ собирается целиком локально на
|
||||||
собирается целиком **локально** на control-хосте (`task image`) и едет на
|
control-хосте (`task image`) и едет на сервер через `docker save`/`load`.
|
||||||
сервер через `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.
|
|
||||||
Конкретная деплой-обвязка (плейбук, секреты) держится в отдельном приватном
|
Конкретная деплой-обвязка (плейбук, секреты) держится в отдельном приватном
|
||||||
репозитории и в комплект не входит.
|
репозитории и в комплект не входит.
|
||||||
|
|
||||||
|
Параметры запуска — сеть, пользователь, монтирования, healthcheck, — разделение
|
||||||
|
ответственности с umbar и единая песочница `/srv/media`:
|
||||||
|
[docs/architecture.md](docs/architecture.md) → «Деплой».
|
||||||
|
|||||||
+1
-1
@@ -11,7 +11,7 @@
|
|||||||
|
|
||||||
Верно одно из трёх:
|
Верно одно из трёх:
|
||||||
|
|
||||||
<!-- копия: adr-когда-заводить из av-dev-pm/skills/canon/references/canon.md -->
|
<!-- копия: adr-когда-заводить из av-dev-docs/skills/canon/references/canon.md -->
|
||||||
- **дорогой откат** — переделка стоит дороже переписывания одного файла;
|
- **дорогой откат** — переделка стоит дороже переписывания одного файла;
|
||||||
- **намеренный отказ** от очевидного подхода;
|
- **намеренный отказ** от очевидного подхода;
|
||||||
- **пересмотр прежнего решения** — тогда у старой записи обязателен статус
|
- **пересмотр прежнего решения** — тогда у старой записи обязателен статус
|
||||||
|
|||||||
@@ -48,8 +48,10 @@
|
|||||||
| `archrules` | собственный анализатор архитектурных правил (часть гейта) | — |
|
| `archrules` | собственный анализатор архитектурных правил (часть гейта) | — |
|
||||||
|
|
||||||
Транспорты приёма — HTTP API, веб-UI, Telegram и CLI (`jellybit add`) — ведут в
|
Транспорты приёма — HTTP API, веб-UI, Telegram и CLI (`jellybit add`) — ведут в
|
||||||
один `ingest`; действия пользователя (apply / refine / reject / defer / undo /
|
один `ingest`; действия пользователя идут командами к `worker`. Перечень команд
|
||||||
retry / delete / dismiss) идут командами к `worker`.
|
и их эффекты — нормативно в [review](../openspec/specs/review/spec.md), пути
|
||||||
|
закрытия и удаления — в
|
||||||
|
[state-reconciliation](../openspec/specs/state-reconciliation/spec.md).
|
||||||
|
|
||||||
## Внешние границы и форматы
|
## Внешние границы и форматы
|
||||||
|
|
||||||
|
|||||||
+2
-1
@@ -214,4 +214,5 @@ erDiagram
|
|||||||
| `ingest.MaxTorrentSize` | `8 MiB` | предел размера принимаемого `.torrent`; проверяется **до** разбора, поэтому bencode-аллокации на эту величину не масштабируются (см. [research/torrent-bencode-limits.md](research/torrent-bencode-limits.md)) |
|
| `ingest.MaxTorrentSize` | `8 MiB` | предел размера принимаемого `.torrent`; проверяется **до** разбора, поэтому bencode-аллокации на эту величину не масштабируются (см. [research/torrent-bencode-limits.md](research/torrent-bencode-limits.md)) |
|
||||||
|
|
||||||
**Ретеншена нет ни у одной таблицы**, лимита на размер тела ответа LLM нет,
|
**Ретеншена нет ни у одной таблицы**, лимита на размер тела ответа LLM нет,
|
||||||
кэша метабаз нет — всё три пункта в беклоге.
|
кэша метабаз нет; состояние по каждому пробелу и заведённые под них задачи —
|
||||||
|
[architecture.md](architecture.md) → «Открытые вопросы».
|
||||||
|
|||||||
+1
-2
@@ -101,8 +101,7 @@ REST API работают **без авторизации** осознанно;
|
|||||||
бесконечный ответ LLM — это вопросы устойчивости и ресурсов
|
бесконечный ответ LLM — это вопросы устойчивости и ресурсов
|
||||||
([architecture.md](architecture.md) → «Эксплуатация»), а не безопасности.
|
([architecture.md](architecture.md) → «Эксплуатация»), а не безопасности.
|
||||||
Отсутствие лимита на размер ответа LLM — известный пробел
|
Отсутствие лимита на размер ответа LLM — известный пробел
|
||||||
([architecture.md](architecture.md) → «Открытые вопросы»); задачей он пока не
|
([architecture.md](architecture.md) → «Открытые вопросы»).
|
||||||
заведён.
|
|
||||||
- **Целостность содержимого медиафайлов.** Что в контейнере mkv — не наша забота.
|
- **Целостность содержимого медиафайлов.** Что в контейнере mkv — не наша забота.
|
||||||
- **Цепочка поставки** — модули Go, базовый образ distroless, плагины тулинга.
|
- **Цепочка поставки** — модули Go, базовый образ distroless, плагины тулинга.
|
||||||
- **Приватность запросов к внешним сервисам.** Названия раздач уезжают в LLM и
|
- **Приватность запросов к внешним сервисам.** Названия раздач уезжают в LLM и
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ qBittorrent и сопоставление его состояний (downloading
|
|||||||
## Requirements
|
## Requirements
|
||||||
### Requirement: Поллинг qBittorrent и сопоставление состояний
|
### Requirement: Поллинг qBittorrent и сопоставление состояний
|
||||||
|
|
||||||
Worker SHALL периодически (`worker.poll_interval`, дефолт 5 с) опрашивать
|
Worker SHALL периодически (`worker.poll_interval`) опрашивать
|
||||||
qBittorrent и сопоставлять его состояния раздачи с состоянием загрузки в БД.
|
qBittorrent и сопоставлять его состояния раздачи с состоянием загрузки в БД.
|
||||||
Готовые к раскладке состояния (`uploading`/`stalledUP`/`pausedUP`/`stoppedUP`/
|
Готовые к раскладке состояния (`uploading`/`stalledUP`/`pausedUP`/`stoppedUP`/
|
||||||
`queuedUP`/`forcedUP`, с учётом различий имён между qBit v4 и v5) SHALL переводить
|
`queuedUP`/`forcedUP`, с учётом различий имён между qBit v4 и v5) SHALL переводить
|
||||||
@@ -39,8 +39,8 @@ API после завершения переноса.
|
|||||||
|
|
||||||
### Requirement: Таймауты-предохранители downloading
|
### Requirement: Таймауты-предохранители downloading
|
||||||
|
|
||||||
Система SHALL переводить `metaDL`/`forcedMetaDL` дольше `magnet_timeout` (дефолт
|
Система SHALL переводить `metaDL`/`forcedMetaDL` дольше `magnet_timeout`
|
||||||
`24h`, редкий предохранитель) в `failed` (`error_code` `magnet_timeout`), а
|
(редкий предохранитель) в `failed` (`error_code` `magnet_timeout`), а
|
||||||
`stalledDL` дольше `stuck_after` — в `stuck` (`error_code`
|
`stalledDL` дольше `stuck_after` — в `stuck` (`error_code`
|
||||||
`stalled`). Возраст система SHALL считать от времени добавления в qBittorrent
|
`stalled`). Возраст система SHALL считать от времени добавления в qBittorrent
|
||||||
(`added_on`), а не от создания задачи, чтобы базис переживал retry и усыновление.
|
(`added_on`), а не от создания задачи, чтобы базис переживал retry и усыновление.
|
||||||
|
|||||||
+7
-5
@@ -2,12 +2,14 @@
|
|||||||
|
|
||||||
Что **можно взять**. Одна задача = один файл `items/<slug>.md`
|
Что **можно взять**. Одна задача = один файл `items/<slug>.md`
|
||||||
+ строка здесь. Целей тут нет — они в [ROADMAP.md](ROADMAP.md): беклог — то, что
|
+ строка здесь. Целей тут нет — они в [ROADMAP.md](ROADMAP.md): беклог — то, что
|
||||||
берут, роадмап — то, подо что берут. Порядка внутри секции нет: «что делать
|
берут, роадмап — то, подо что берут. Ведётся скиллом `av-dev-tasks:tasks`.
|
||||||
дальше» отвечает набор спринта. Ведётся скиллом `tasks`.
|
|
||||||
|
|
||||||
Секции «блокеры» здесь нет и не заводится: блокер — это состояние
|
**Порядок строк внутри секции — это приоритет.** Первая строка секции — то, что
|
||||||
(спринт не может продолжаться ни одной задачей), оно живёт до ответа
|
делают следующим. Порядок назначает человек на груминге
|
||||||
человека, а его следы — вопросами в файлах задач.
|
(`av-dev-tasks:groom`), машина его не выводит.
|
||||||
|
|
||||||
|
Секции «блокеры» здесь нет и не заводится: блокер — это состояние, оно живёт до
|
||||||
|
ответа человека, а его следы — вопросами в файлах задач.
|
||||||
|
|
||||||
## Ядро продукта
|
## Ядро продукта
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user