Files
jellybit/docs/adr/ADR-2026-08-06-spec-follows-code-on-narrow-window.md
T
av 30ee598547 download-tracking: требование о re-read source_type приведено к коду
- re-read `source_type` перечитывается под блокировкой после тик-снимка, а
  остаточное окно вывода имени названо известным ограничением с ценой и
  достоверным маршрутом восстановления (ручной шаг + `Retry`, не самоисцеление)
- в `ingest` снята парная ложная гарантия «воркер добавит раздачу файлом»,
  добавлены сценарии на оба окна апгрейда и на недоступные байты `.torrent`
- заведён ADR о том, что при разрыве спека↔код двигается тот, чья формулировка
  сильнее рационали
2026-08-06 14:44:21 +03:00

81 lines
6.5 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Спека следует за кодом, когда гарантия недостижима, а окно узкое
- **Дата:** 2026-08-06
- **Источник:**
[openspec/changes/archive/2026-08-06-catched-source-type-reread-wording/design.md](../../openspec/changes/archive/2026-08-06-catched-source-type-reread-wording/design.md)
## Решение
Требование `download-tracking` о re-read `source_type` приведено **к коду**, а
не наоборот: перечитывать под блокировкой переходов **после тик-снимка**, а
остаточное окно (апгрейд magnet → `.torrent`, легший в вызов namer'а) названо в
спеке известным ограничением с ценой и маршрутом восстановления. Код не тронут.
Общее правило, которое отсюда следует для проекта: когда спека и код разошлись,
**двигается тот, чья формулировка сильнее рационали**. Требование, обещавшее
больше, чем нужно ради его собственной причины, чинится текстом; недостающая
гарантия чинится кодом.
## Почему
Формулировка была сильнее своей же рационали:
> Рациональ исходного требования — «не полагаться на снимок, снятый ранее вне
> блокировки» — выполнен первым re-read под замком. Формулировка «непосредственно
> перед добавлением» была сильнее рационали и кодом не достигается: между
> re-read и `qbt.Add` стоит namer, вынесенный из-под блокировки намеренно
> (требование «Медленные вызовы SHALL выполняться вне блокировки»).
Цена починки кодом оказалась несоразмерной ущербу:
> Вариант A (пересобирать `addReq` из `before` под замком) отклонён: это не
> однострочник — `sourceAddParts` читает байты `.torrent` и держать его под
> блокировкой нельзя, а при апгрейде корректен был бы и повторный вызов namer'а
> (подсказка имени берётся из другого источника).
Главное же — **молчащая ложная гарантия дороже названного ограничения**. Пока
спека утверждала недостижимое, дефект был невидим ровно потому, что нормативный
дом поведения его отрицал; аудит capability находил его заново.
## Рассмотренные варианты
- **A — починить код** (пересобирать запрос на добавление из свежей записи под
блокировкой). Отвергнут по цене: чтение блоба `.torrent` под замком
недопустимо, корректная версия тянет повторный вызов namer'а. Отвергнут
**отложенно, а не окончательно**: спека поэтому не запрещает его нормативно
(см. `design.md` D6).
- **B — привести спеку к коду** (принято). Наблюдаемое поведение прежнее,
меняется заявленное.
- **C — оставить как есть.** Отвергнут: расхождение спека↔код воспроизводится
каждым аудитом, а читатель спеки считает окно закрытым.
## Последствия
- `+` Нормативный дом поведения перестал утверждать недостижимое; ограничение
видно и имеет названную цену вместо молчания.
- `+` Парная ложная гарантия снята и в `ingest` («воркер добавит раздачу
файлом») — иначе она бы просто переехала в соседнюю capability и всплыла
следующим аудитом.
- `+` Заодно назван исход ветки «сохранённые байты `.torrent` недоступны», не
заказанной до этого ни одним сценарием.
- `` Цена окна выше, чем считала постановка задачи: не «подождать и нажать
`Retry`», а ожидание `magnet_timeout` (дефолт `24h`) **плюс ручной шаг**
убрать зависшую раздачу из qBittorrent. `Retry` сам не добивает: `metaDL`
считается живым и здоровым торрентом, и `Retry` к нему перецепляется без
повторного `add` (`design.md` D2). На этой пересмотренной цене вопрос
«чинить ли окно кодом» открыт заново.
- `` Новая нормативная ветка (недоступные байты `.torrent`) держится на чтении
кода: теста-оракула у неё нет, её регрессия зелёный гейт не покрасит.
- `` Прецедент «спека следует за кодом» опасен буквальным применением. Он
оправдан **только** когда формулировка сильнее рационали и ущерб от разрыва
назван; «код так делает, значит так и запишем» этой записью не
санкционируется.
## Триггер пересмотра
Записан отдельно, чтобы не гонять круг заново:
> Окно возвращается в работу вариантом A, когда апгрейд в вызове namer'а
> случится в эксплуатации хотя бы раз — признак в логах — либо когда стоимость
> ручного шага станет заметной. До того — принято и описано.