docs: документы дополнены материалом для ревью

- review.md: заведён род узла «вызов LLM и разбор ответа», добавлены вопросы
  тем autotests, security и operations, маршрут к уже механизированному
- architecture.md: «Открытые вопросы» вместо «пока нет» — восемь областей
  знаемо тонкого устройства со ссылкой на задачу
- security.md: снят указатель на несуществующую задачу про лимит ответа LLM
This commit is contained in:
av
2026-08-07 13:47:52 +03:00
parent b879c049ea
commit a47a767691
3 changed files with 64 additions and 3 deletions
+15 -2
View File
@@ -170,5 +170,18 @@ Jellyfin указывают на `movies`/`series`, а не на корень
## Открытые вопросы ## Открытые вопросы
- Пока нет. Решённое разъехалось по ADR и capability-спекам; то, что требует Места, где устройство знаемо тонкое: не дефекты, а принятые пока пробелы. Здесь
работы, живёт задачами в [tasks/BACKLOG.md](tasks/BACKLOG.md). только адрес и одна фраза — что именно не сделано; работа под каждым живёт
задачей в [tasks/BACKLOG.md](tasks/BACKLOG.md). Список нужен ревью: правка,
попавшая в такую область, стоит дороже, чем выглядит.
| Область | Чего нет сегодня | Задача |
| --- | --- | --- |
| Масштаб | ориентир 100/1000 загрузок не зафиксирован, узкие места SQLite, воркера и поллинга не измерены | `scale-100-downloads` |
| Ретеншен | терминальные задачи и сырые ответы LLM копятся вечно, авточистки нет | `db-retention-cleanup` |
| Бекап | бекапить `/data` требуется, а стратегия и ротация не описаны | `sqlite-backup` |
| Наблюдаемость | healthcheck проверяет только сам сервис; метрик и алертинга нет, отказ виден по застрявшей задаче | `deep-healthcheck-dependencies` |
| Идентичность раздачи | split v1/v2-хеши не связаны, паре `xt` из магнета доверяем | `infohash-identity-integrity` |
| Расход внешних лимитов | кэша ответов метабаз нет, повтор распознавания бьёт провайдера заново | `metadata-cache` |
| История переходов | хранится только текущее состояние, «как сюда попали» восстанавливается по логам | `download-transition-history` |
| Предел ответа LLM | лимита на размер ответа нет — единственный недоверенный канал без предела; задачей пока не заведено | — |
+46
View File
@@ -6,6 +6,17 @@ Go-сервиса и что здесь уже проскакивало. Устр
## Как настроен конвейер ## Как настроен конвейер
**Прежде чем задать вопрос, посмотри, не задан ли он уже машиной.** Перечень
механизированного — [conventions/README.md](conventions/README.md) →
«Механизировано»; чем безусловно краснеет гейт и чего в нём намеренно нет —
[CLAUDE.md](../CLAUDE.md) → «Гейт». Вопрос про уже проверенное вытесняет вопрос
про непроверенное — места в прогоне столько же.
**Severity не выводится проходом заново.** Она стоит рядом с формулировкой
инварианта в [CLAUDE.md](../CLAUDE.md) → «Инварианты», обратимость — там же в
«Работа» → «Необратимое». Шкала ущерба берётся оттуда, а порядок ценностей —
из [security.md](security.md) → «Что чувствительнее чего».
### Типовые узлы ### Типовые узлы
Рода узлов проекта и проверяемые свойства к каждому. Род, а не инвентарь Рода узлов проекта и проверяемые свойства к каждому. Род, а не инвентарь
@@ -54,6 +65,23 @@ Go-сервиса и что здесь уже проскакивало. Устр
- невалидный вход даёт доменную ошибку, а не тихий дефолт; - невалидный вход даёт доменную ошибку, а не тихий дефолт;
- результат нормализуется на границе (lowercase hex, trim, `ident.Parse`). - результат нормализуется на границе (lowercase hex, trim, `ident.Parse`).
**Вызов LLM и разбор его ответа** (`recognize`, `naming.Derive`)
Самый специфичный род узла в проекте: единственный, чей выход недетерминирован,
недоверен и стоит денег одновременно.
- решение узла **не является гейтом безопасности**: инъекция в промпт считается
состоявшейся, защита стоит ниже — на валидации целевого пути
([security.md](security.md));
- самооценка модели не заменяет матч в метабазе — порог `confidence` стоит
**поверх** матча дополнительным условием, а не вместо него;
- разбор ответа устойчив к лишним и недостающим полям, обрезке и не-JSON;
негодный ответ даёт доменную ошибку, а не тихий дефолт;
- попытка стоит лимита и денег: число ретраев берётся из конфига, а фоновый цикл
не запускает распознавание сам по себе повторно;
- тест не ходит в живой эндпоинт — провайдер за интерфейсом, ответ фикстурой;
живые прогоны только за env-гейтом.
**htmx-хендлер** **htmx-хендлер**
- один партиал обслуживает страницу и фрагмент, ветвление по `isHTMX`; - один партиал обслуживает страницу и фрагмент, ветвление по `isHTMX`;
@@ -121,6 +149,15 @@ Go-сервиса и что здесь уже проскакивало. Устр
(задача про масштаб 100/1000, [database.md](database.md) → «Настройки») (задача про масштаб 100/1000, [database.md](database.md) → «Настройки»)
- `operations`: что остаётся на диске и в базе, если процесс убит посреди - `operations`: что остаётся на диске и в базе, если процесс убит посреди
раскладки батча? (состояние `linking` и его восстановление) раскладки батча? (состояние `linking` и его восстановление)
- `autotests`: изменённые строки не просто исполнены тестом, а **проверены**
есть ли тест, который упал бы без этой правки? (diff-coverage в гейте меряет
исполнение, отличить его от проверки машина не может)
- `autotests`: конкурентная часть правки проверена тестом, а не рассуждением?
(`-race` без gcc уходит в `SKIP`, и тогда гонки не проверял никто —
[CLAUDE.md](../CLAUDE.md) → «Гейт»)
- `autotests`: новый тест не ходит в живой qBittorrent, LLM, метабазу или
Telegram — а если ходит, он за env-гейтом в `*_integration_test.go`?
([CLAUDE.md](../CLAUDE.md) → «Запреты»)
- `conventions`: логирующий чекпоинт один на операцию — или ошибка залогирована - `conventions`: логирующий чекпоинт один на операцию — или ошибка залогирована
и возвращена вверх, где залогирована снова? и возвращена вверх, где залогирована снова?
([conventions/logging.md](conventions/logging.md)) ([conventions/logging.md](conventions/logging.md))
@@ -129,6 +166,15 @@ Go-сервиса и что здесь уже проскакивало. Устр
([conventions/config.md](conventions/config.md)) ([conventions/config.md](conventions/config.md))
- `requirements`: не завелось ли поведение, которого спека не заказывала — тихий - `requirements`: не завелось ли поведение, которого спека не заказывала — тихий
дефолт, проглоченная ошибка, ретрай «на всякий случай», отброшенное поле? дефолт, проглоченная ошибка, ретрай «на всякий случай», отброшенное поле?
- `security`: читается ли тело ответа внешнего сервиса целиком без предела —
лимита на размер ответа LLM в проекте нет, и это единственный недоверенный
канал, где предел не стоит ([security.md](security.md) → «Что вне модели»)
- `operations`: не удваивает ли новая ветка расход лимита метабаз и платного
LLM — повтор, ретрай, «распознать заново» на том же входе? (кэша ответов нет,
задача `metadata-cache`)
- `operations`: копится ли то, что заводит это изменение, без срока хранения —
строки терминальных задач, сырые ответы, файлы? (авточистки в проекте нет,
задача `db-retention-cleanup`)
- `architecture`: не появился ли второй способ делать то, что уже делается — - `architecture`: не появился ли второй способ делать то, что уже делается —
второе место, где генерится время или id, второй парсер источника, вторая второе место, где генерится время или id, второй парсер источника, вторая
логика целевых имён мимо `naming`? логика целевых имён мимо `naming`?
+3 -1
View File
@@ -100,7 +100,9 @@ REST API работают **без авторизации** осознанно;
- **Отказ в обслуживании изнутри контура.** Огромная раздача, тысяча файлов, - **Отказ в обслуживании изнутри контура.** Огромная раздача, тысяча файлов,
бесконечный ответ LLM — это вопросы устойчивости и ресурсов бесконечный ответ LLM — это вопросы устойчивости и ресурсов
([architecture.md](architecture.md) → «Эксплуатация»), а не безопасности. ([architecture.md](architecture.md) → «Эксплуатация»), а не безопасности.
Отсутствие лимита на размер ответа LLM — известный пробел, задача в беклоге. Отсутствие лимита на размер ответа LLM — известный пробел
([architecture.md](architecture.md) → «Открытые вопросы»); задачей он пока не
заведён.
- **Целостность содержимого медиафайлов.** Что в контейнере mkv — не наша забота. - **Целостность содержимого медиафайлов.** Что в контейнере mkv — не наша забота.
- **Цепочка поставки** — модули Go, базовый образ distroless, плагины тулинга. - **Цепочка поставки** — модули Go, базовый образ distroless, плагины тулинга.
- **Приватность запросов к внешним сервисам.** Названия раздач уезжают в LLM и - **Приватность запросов к внешним сервисам.** Названия раздач уезжают в LLM и