docs: ТЗ v2 — QR-доступ, меню разделов, коммит по дереву, агент со стражем, общие алерты

ADR-011 (QR-приглашения), ADR-012 (командная модель), ADR-013 (агент логов).

Refs #24

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-13 22:50:31 +03:00
co-authored by Claude Opus 5.5
parent af1585c634
commit d34bc33aeb
5 changed files with 364 additions and 200 deletions
+25 -1
View File
@@ -63,7 +63,7 @@
**Последствия:** вся логика песочницы — в одном месте и тестируется отдельно.
## ADR-007: LLM строит структурированный запрос, а не shell-команду
**Дата:** 2026-10-12 · **Статус:** принято
**Дата:** 2026-10-12 · **Статус:** принято, дополнено ADR-013
**Контекст:** идея — «LLM формирует grep по логам». Логи содержат текст, подконтрольный пользователю (prompt injection).
**Решение:** LLM возвращает JSON `LogQuery` (источник, период, regex, уровень, лимит) по схеме; бот валидирует и выполняет поиск сам, в Python, с таймаутом regex. Пользователю показывается эквивалентный grep.
@@ -96,3 +96,27 @@
- Триггер `pull_request` в SourceCraft не срабатывает (PR живут в Gitea) → CI бота запускается на `push` во все ветки.
- Токен SourceCraft хранится в настройках зеркала Gitea → нужен отдельный токен с доступом только к `tgit`.
- Issues #1–#21 перенесены из SourceCraft с теми же номерами; в SourceCraft закрыты со ссылкой.
## ADR-011: Доступ — только по одноразовым QR-приглашениям
**Дата:** 2026-10-13 · **Статус:** принято
**Контекст:** бот коммитит в общий репозиторий и запускает код на сервере — случайный человек, нашедший бота, не должен ничего сделать или заспамить.
**Решение:** приглашение = deep link `t.me/<bot>?start=<token>` в виде QR; токен 128 бит, одноразовый, 24 ч, в БД — только хэш. Проверка доступа — middleware на каждом апдейте (сообщения и кнопки). Неавторизованным — одна фраза в сутки, дальше игнор; антиперебор 5 попыток/час. Первые админы — `ADMIN_IDS` в `.env`.
**Альтернативы:** белый список Telegram ID вручную — неудобно (надо узнавать ID); пароль в `/start` — передаётся и утекает как текст; многоразовый QR — одна утечка открывает доступ всем.
**Последствия:** нужен раздел «Участники» для админов (выпуск QR, список, отзыв); библиотека `segno` для QR.
## ADR-012: Командная модель — общий репозиторий, общие сервисы, алерты всем
**Дата:** 2026-10-13 · **Статус:** принято (заменяет «проекты с владельцами» из SPEC v1)
**Контекст:** v2 требует, чтобы алерты получали все авторизованные, а коммит шёл интерактивно по дереву репозитория.
**Решение:** все участники равноправно работают с одним репозиторием загрузок (`main`) и видят все сервисы; сервис = папка `services/<name>/`; у каждого участника свой черновик; алерты рассылаются всем (кроме 🛡 — только админам).
**Альтернативы:** проекты с владельцами (v1) — противоречит «алерты всем» и усложняет навигацию правами.
**Последствия:** права проще (участник/админ); риск, что участник сломает чужой сервис, — принимаем: история коммитов с автором в трейлере, CI-гейт, откат (P2).
## ADR-013: Агент логов — фильтр, LLM-страж и планировщик раздельно; логи в LLM не передаются
**Дата:** 2026-10-13 · **Статус:** принято
**Контекст:** промт пользователя может быть попыткой сломать или взломать систему; логи содержат текст, подконтрольный сервисам (injection).
**Решение:** конвейер из пяти шагов (SPEC §4.3.1): детерминированный фильтр → отдельный LLM-вызов «страж» с JSON-вердиктом `safe|attack` (невалидный ответ = `attack`) → отдельный LLM-вызов «планировщик», который получает только промт и список контейнеров и возвращает `LogQuery` → валидация → выполнение в Python. Пользователю показывается итоговый grep и найденные строки. Атака → отказ + алерт админам.
**Альтернативы:** один вызов LLM с инструкцией «откажись, если атака» — страж и исполнитель в одном контексте, injection обходит оба; передавать логи в LLM для поиска — injection из логов и утечка секретов.
**Последствия:** два LLM-вызова на запрос (латентность, токены → квота 30/сутки); даже при обходе стража вред ограничен схемой `LogQuery`.