- имя раздачи нормализуется на границе разбора: вырожденное `-` (metainfo.NoName) даёт пустое имя, пробельное схлопывается — сентинел больше не доходит ни до контекста распознавания, ни до source_ref, ни до подсказки вывода имени - контракт «на любом пути ошибки приёма результат нулевой» объявлен в ingest и удерживается структурно; три транспорта перестали обещать идентификатор, которого нет, и коррелируют отказ по request_id - scoped-логгер загрузки ставится до вызова внешнего сервиса в семи командах воркера — записи об отказе qBittorrent и метабаз получили download_id и infohash; граница разбора bencode записана в docs/research
13 KiB
13 KiB
Чекпоинт 1 — ревью предложения, профиль design
- Change:
ingest-nits - База диффа:
master(5c79fdfffe9e2ddc78b7ebf9f4cdc3aa83560b2b); кода на ветке на момент прогона не было. - Профиль:
design. Режим прогона:по графу(все три прохода одной волной — граф профиля плоский, машину не держит никто). - Дата: 2026-08-06.
Запущенные проходы и исход
| Проход | Исход |
|---|---|
review-specs |
6 находок (2 major, 4 minor) + 5 границ спеки |
review-rubric (фаза 1) |
рубрика из 12 свойств, 8 находок (2 major, 6 minor), 5 promote-кандидатов |
review-architecture |
2 находки (обе major) + 3 пункта «дешевле переделать до мерджа» |
Триаж на этом чекпоинте не запускается — так устроен профиль: находок единицы, каждая либо правит спеку, либо становится записанным вопросом. Сведение сделал оркестратор пайплайна.
Что отработано инлайн
Дедуплицировано по причине; в скобках — кто нашёл.
- Фактическое основание N1 было неверным (
specs,major, оракул — прогон крафт-входов черезmetainfo.Load). Библиотека сентинел-не синтезирует:BestName()на раздаче без имени возвращает пустую строку, аNoNameприсваивается только при авторинге. Значит-доходит до нас лишь от раздачи, объявившей его полемname. Следствия: критерий приёмки постановки выполнялся до изменения; случай «раздача безname» не был покрыт вовсе; неверный комментарий вinternal/torrent/torrent_test.go:224и есть источник исходной ошибки ревью 2026-07-08. → требование, дизайн и предложение переписаны по наблюдению; два входа разведены сценариями и тестами; комментарий теста правится. - Требование
identityзаявляло больше, чем change делает (architectureиspecs, обаmajor): обязанность формулировалась как «до первого вызова, способного что-либо записать», и поимённо называлаcancel/dismiss, которые change сознательно не трогает. Нормативная спека стала бы ложной в момент архивации. → обязанность сужена до вызова внешнего сервиса. request_idвменялся всем транспортам, а существует только на HTTP (architecturemajor,specsminor,rubricmajor). → требование называет ключ поимённо по транспортам; для Telegram зафиксировано отсутствие ключа как сегодняшнее состояние, вопрос записан вdesign.md→ Open Questions. Регрессии нет:res.DownloadIDуже сегодня всегда пуст.- Telegram числился среди
ext.*-клиентов, которых у него нет (specs,minor). → убран; перечень клиентов не дублируется, а отдан конвенции. - Третий вызов приёма (
handleUIAdd, веб-форма) отсутствовал в задачах (specs,minor). → добавлен пункт 2.4; иначе требование было бы выполнено на две трети. - Заявленная однородность с фильтром magnet-заглушек ложна (
specs,minor): у magnet заглушкаdnфильтруется только в контексте, а в подсказку имени уходит. → различие названо явно, распространение на magnet объявлено отдельным изменением. - Спека утверждала абсолют «ниже по потоку сентинел не встречается», а путь
файла его выпускает (
rubric,minor). → нормализуемые поля перечислены поимённо, про пути файлов сказано, почему они не нормализуются. - Имя с переводом строки подменяет строки построчного контекста (
rubric,major). → нормализация расширена на разделители строк и краевые пробелы тем жеoneLine, что уже применён к комментарию. В требовании прямо сказано, что защитой от инъекции в промпт это не является: пользовательский текст многострочен по замыслу. - Контракт «результат пуст» держался перечнем веток (
rubric,minor). → удерживается структурно: именованный возврат + одинdefer; тест сравнивает результат с нулевым значением целиком. - У третьего потребителя
DisplayName(подсказка namer) не было оракула (rubric,minor). → добавлен пункт 1.5, тест вinternal/worker. - Тест записи о
Fails.проверял только наличие полей (rubric,minor). → добавлена негативная половина:passkeyотправленного magnet в записи не встречается. Инвариант «секреты не в логи» —major. - Сценарий требовал
infohashтам, где тело требования смягчало до «когда известен» (specs, граница спеки). → в GIVEN добавлено «с известным инфохэшем». - Каталог
docs/research/тихо расширялся с чужих данных на чужой код (architecture). → вводная README расширяется, записка получает условие устаревания.
Записанные вопросы
Оба — в design.md → Open Questions, оба с вариантами, ценой и рекомендацией.
- Нужен ли Telegram-транспорту собственный корреляционный ключ у отказа приёма.
Рекомендация — поднять запись отказа разбора до
INFOсinfohashотдельной задачей, а не заводить второй канал корреляции. - Приводить ли
Cancel/Dismissк формеctx = w.scoped(…). Рекомендация — отдельной задачей-гигиеной, когда в них появится первый внешний вызов.
Урожай (заведение задач — не работа пайплайна)
- Заглушка
dnвида*-topic-<id>уходит в подсказку вывода имени, хотя из контекста отфильтрована (worker.sourceAddParts→magnet.Parse→DisplayName,internal/worker/worker.go:626). Симметрично N1, но на magnet-ветке. Правка требует изменения действующего требования «Синтез контекста распознавания из полей magnet» (сценарий «Строки-факты не становятся отображаемым именем»), поэтому в границы этой задачи не входит. Оракул: тест на подсказку для голого magnet с заглушкой. Провенанс:specs, changeingest-nits. infohashв записи о внешнем вызове снимается со снимка загрузки, а не с того, с чем вызов ушёл (rubric,low). Сегодня значения совпадают; расхождение возможно у загрузки с несколькими хешами (v1+v2). Класс совпадает с журналом 2026-08-06 (признак снят с одной сущности, действие применено к другой), но стоит здесь только разбора, не данных.- Пустой
source_refу torrent-загрузки возможен:.torrentс именем-и без имени присланного файла. Действующее требование велитsource_refбыть человекочитаемым референсом, но случая «нет ни того, ни другого» не описывает. Дыра не новая, но изменение проходит ровно по ней. Провенанс:specs, границы спеки. - Отказ разбора источника пишется на
DEBUG(internal/ingest/ingest.go), то есть на боевомINFOне пишется вовсе — для Telegram-пути это означает, что у отказа приёма нет ни ключа у пользователя, ни записи в журнале. Связано с записанным вопросом 1. - Promote candidates (
rubric): (а) «scoped-логгер загрузки строится один раз, на входе публичной команды воркера» →docs/conventions/logging.mdплюс механизация тестом-перебором; (б) «нормализация недоверенного имени на границе — это вырожденные значения, краевые пробелы и разделители строк» →docs/review.md, «Парсер недоверенного входа»; (в) «у каждого транспорта назван свой корреляционный ключ публичного канала» →docs/conventions/errors.md; (г) «тест клиента внешнего сервиса проверяет и отсутствие секретосодержащих значений» →docs/conventions/logging.md.
Границы покрытия
- Гейт на этом чекпоинте не запускался — кода на ветке не было; это
устройство профиля
design, а не пропуск. - Триаж не запускался — в профиле
designего нет по построению; сведение и дедупликацию находок сделал оркестратор пайплайна, то есть тот же, кто писал предложение. Разведённости приёмщика и исполнителя на этом чекпоинте нет. - Не запускались проходы
code,adversary,ops,reimpl— они не входят в профильdesignи работают после apply (чекпоинт 2). - Замер аллокаций bencode на этом чекпоинте не воспроизводился ни одним
проходом:
specsпроверил только провенанс ссылок по исходникам библиотеки. Сам замер — задача 4.1, его исход проверяет чекпоинт 2. - Ни один проход не открывал живой qBittorrent, LLM и метабазы — запрещено
CLAUDE.md→ «Запреты». - Ценность самой постановки («нужно ли закрывать эти четыре нити») ревью не оценивает ни в одном профиле.