From a47a7676915eb5e95a06cb3c824884a2e3620d76 Mon Sep 17 00:00:00 2001 From: Anton Vakhrushev Date: Fri, 7 Aug 2026 13:47:52 +0300 Subject: [PATCH] =?UTF-8?q?docs:=20=D0=B4=D0=BE=D0=BA=D1=83=D0=BC=D0=B5?= =?UTF-8?q?=D0=BD=D1=82=D1=8B=20=D0=B4=D0=BE=D0=BF=D0=BE=D0=BB=D0=BD=D0=B5?= =?UTF-8?q?=D0=BD=D1=8B=20=D0=BC=D0=B0=D1=82=D0=B5=D1=80=D0=B8=D0=B0=D0=BB?= =?UTF-8?q?=D0=BE=D0=BC=20=D0=B4=D0=BB=D1=8F=20=D1=80=D0=B5=D0=B2=D1=8C?= =?UTF-8?q?=D1=8E?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - review.md: заведён род узла «вызов LLM и разбор ответа», добавлены вопросы тем autotests, security и operations, маршрут к уже механизированному - architecture.md: «Открытые вопросы» вместо «пока нет» — восемь областей знаемо тонкого устройства со ссылкой на задачу - security.md: снят указатель на несуществующую задачу про лимит ответа LLM --- docs/architecture.md | 17 ++++++++++++++-- docs/review.md | 46 ++++++++++++++++++++++++++++++++++++++++++++ docs/security.md | 4 +++- 3 files changed, 64 insertions(+), 3 deletions(-) diff --git a/docs/architecture.md b/docs/architecture.md index 3a9bc6d..cd4aca7 100644 --- a/docs/architecture.md +++ b/docs/architecture.md @@ -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 | лимита на размер ответа нет — единственный недоверенный канал без предела; задачей пока не заведено | — | diff --git a/docs/review.md b/docs/review.md index b141aa3..b6683a0 100644 --- a/docs/review.md +++ b/docs/review.md @@ -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`). +**Вызов LLM и разбор его ответа** (`recognize`, `naming.Derive`) + +Самый специфичный род узла в проекте: единственный, чей выход недетерминирован, +недоверен и стоит денег одновременно. + +- решение узла **не является гейтом безопасности**: инъекция в промпт считается + состоявшейся, защита стоит ниже — на валидации целевого пути + ([security.md](security.md)); +- самооценка модели не заменяет матч в метабазе — порог `confidence` стоит + **поверх** матча дополнительным условием, а не вместо него; +- разбор ответа устойчив к лишним и недостающим полям, обрезке и не-JSON; + негодный ответ даёт доменную ошибку, а не тихий дефолт; +- попытка стоит лимита и денег: число ретраев берётся из конфига, а фоновый цикл + не запускает распознавание сам по себе повторно; +- тест не ходит в живой эндпоинт — провайдер за интерфейсом, ответ фикстурой; + живые прогоны только за env-гейтом. + **htmx-хендлер** - один партиал обслуживает страницу и фрагмент, ветвление по `isHTMX`; @@ -121,6 +149,15 @@ Go-сервиса и что здесь уже проскакивало. Устр (задача про масштаб 100/1000, [database.md](database.md) → «Настройки») - `operations`: что остаётся на диске и в базе, если процесс убит посреди раскладки батча? (состояние `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/logging.md](conventions/logging.md)) @@ -129,6 +166,15 @@ Go-сервиса и что здесь уже проскакивало. Устр ([conventions/config.md](conventions/config.md)) - `requirements`: не завелось ли поведение, которого спека не заказывала — тихий дефолт, проглоченная ошибка, ретрай «на всякий случай», отброшенное поле? +- `security`: читается ли тело ответа внешнего сервиса целиком без предела — + лимита на размер ответа LLM в проекте нет, и это единственный недоверенный + канал, где предел не стоит ([security.md](security.md) → «Что вне модели») +- `operations`: не удваивает ли новая ветка расход лимита метабаз и платного + LLM — повтор, ретрай, «распознать заново» на том же входе? (кэша ответов нет, + задача `metadata-cache`) +- `operations`: копится ли то, что заводит это изменение, без срока хранения — + строки терминальных задач, сырые ответы, файлы? (авточистки в проекте нет, + задача `db-retention-cleanup`) - `architecture`: не появился ли второй способ делать то, что уже делается — второе место, где генерится время или id, второй парсер источника, вторая логика целевых имён мимо `naming`? diff --git a/docs/security.md b/docs/security.md index a9de23d..18046bf 100644 --- a/docs/security.md +++ b/docs/security.md @@ -100,7 +100,9 @@ REST API работают **без авторизации** осознанно; - **Отказ в обслуживании изнутри контура.** Огромная раздача, тысяча файлов, бесконечный ответ LLM — это вопросы устойчивости и ресурсов ([architecture.md](architecture.md) → «Эксплуатация»), а не безопасности. - Отсутствие лимита на размер ответа LLM — известный пробел, задача в беклоге. + Отсутствие лимита на размер ответа LLM — известный пробел + ([architecture.md](architecture.md) → «Открытые вопросы»); задачей он пока не + заведён. - **Целостность содержимого медиафайлов.** Что в контейнере mkv — не наша забота. - **Цепочка поставки** — модули Go, базовый образ distroless, плагины тулинга. - **Приватность запросов к внешним сервисам.** Названия раздач уезжают в LLM и