Files
transcriber/openspec/changes/archive/2026-08-15-app-json-contract/review/design-review.md
T
av 3a2da3004b приём и чтение записей сведены к одному контракту приложения
- адреса приложения переехали в своё пространство `/app/`, опрос готовности
  убран целиком: рубеж и причину остановки владелец узнаёт карточкой записи,
  текст — отдельным адресом названного вида
- заведена единая точка отображения доменной ошибки и слой, приводящий к той же
  форме отказы библиотеки: тело несёт машиночитаемый код рядом с сообщением
- у записи появились имя файла отправителя, длительность и размер своими
  колонками, а у ленты владельца — свой индекс: без него страница сканировала
  весь архив сервиса
2026-08-15 13:51:23 +03:00

12 KiB

Ревью дизайна — app-json-contract

Метка large, режим «по графу». Разметка: размер крупное, сложность незнакомое; метку назвал агент review-scope до написания артефактов.

Состав по метке: specs (режим «дизайн ДО кода»), rubric, architecture плюс вопрос автору о трёх формах решения. Гейта на этой стадии нет — кода не существует; триажа нет — сток стадии это отработка замечаний.

Что найдено и что с этим сделано

Находок пятнадцать на три прохода, пересечения сведены.

Отработано правкой спек и дизайна

Находка Проход Правка
Инвариант «запись не теряется молча» и два требования pipeline ссылались на убранный опрос готовности specs заведена дельта pipeline; карточка обязана нести рубеж, признак остановки и причину; в план добавлена правка CLAUDE.md
Состав полей карточки не нормирован, хотя на него ссылается intake specs карточка = элемент страницы плюс перечень доступных видов; имена полей названы поимённо
Перечень значений рубежа потерян вместе с убранным требованием specs возвращён нормой «принадлежит перечню рубежей конвейера», без перечисления порознь
Коды отказа на адресах чтения не заказаны; потерян запрет на разницу ответов без сессии specs перечень кодов закрыт и назван; 401 до всякого чтения записи; сценарий возвращён
«Вид текста» в archive значил форму показа, в storage — вид; вычитанный текст недостижим specs один закрытый перечень transcript/literary/replicas
Признак наличия текста булев, а состояние «текст есть, реплик нет» достижимо rubric перечень доступных видов вместо признака
«Текста ещё нет» без названного кода сливалось бы с 404 чужой записи rubric, specs код 409, сценарий на отличие от 404
Тело отказа несло только русскую фразу rubric два поля: машиночитаемый код из закрытого перечня и сообщение
Имена и единицы двух колонок из трёх не названы перед необратимым шагом схемы rubric, architecture original_filename, duration_ms, size_bytes; неизвестная длительность отличима от нулевой
Потолок размера страницы не назван — параметр обходит постраничность rubric, specs умолчание, потолок, усечение, 400 на негодное значение
Отказ по превышению размера тела шёл мимо единой формы rubric своя доменная ветвь, код 413, предел в теле числом
Имена полей ответа не названы нигде architecture названы; форма страницы взята той же, какой её отдаёт хранилище
Отбор «в работе» — второй толкователь рубежей, остановленная запись выпадала из обеих половин architecture, specs три состояния вместо двух; предикаты выводятся из дескриптора рубежа; правило archrules на нового потребителя
Ветви 401, 403, 413 отсутствуют в таблице docs/conventions/errors.md, объявленной источником единой точки architecture шаг плана на правку конвенции
Два адреса обещаны дизайном, но не названы спекой specs обещание снято: названным считается то, что стоит требованием

Ушло на чекпоинт человеку

Три развилки — каждая расходится с тем, что владелец назвал в постановке, и каждая необратима после мерджа.

  1. Длительность и размер колонками записи против батч-разрешения строки файла. Обе величины уже лежат строкой файла; довод «по строке на запись списка» опровергается собственным шагом плана — темы разрешаются одним запросом на страницу. Цена ошибки: две вечные колонки-копии в применённом шаге схемы, равенство которых не держит ничто.
  2. Перечень известных расширений в GET /app/config. У сервиса нет понятия «принимаемые форматы» — единственный такой перечень сужает метку метрики и имеет другой смысл. Приложение прочитает перечень как «что можно загружать» и станет единственным местом, где это правило существует.
  3. Постраничное чтение номером страницы против курсора. Приём пишет в голову той же ленты, которую читает список: запись, заведённая между двумя страницами, сдвигает окно — один элемент придёт дважды, другой не придёт никогда, и оба раза молча.

Второй круг: разметка и сверка после чекпоинта

Правки после чекпоинта тронули дельта-спеки, поэтому повторены разметка и та часть ревью дизайна, которой правка касается. Рубрика и архитектурный проход не перезапускались намеренно: принятые правки — их же собственные рекомендации, и судить их своим отчётом они не могут.

Разметка не сдвинулась — крупное, незнакомое, large, теми же пятью источниками. Правка синхронизировала спеки с решениями, уже стоявшими в дизайне, а не добавила площадь или неизвестность.

Повторная сверка дала пять находок, все отработаны:

Находка Правка
MODIFIED требования pipeline вырезало обоснование двух сторожей — задача failure-verdict-vs-retry прочла бы урезанную норму предложение возвращено целиком, сменён только держатель нормы
Критерии приёмки остались на прежней модели текста и вернули бы в код две уже закрытые находки: булев признак наличия текста и «тот же вид репликами»; оракул формы сравнивал не ту пару критерии и шаги плана приведены к спеке, правка помечена в самом критерии
Половина имён публичного контракта осталась бы за кодом — поля тела отказа и сам перечень кодов, поля пределов и «кто вошёл», имя признака повтора, имена параметров запроса все названы спекой поимённо
Два предела из объявляемых не имели проверяемого источника; имя «частота опроса готовности» протухало вместе с убираемым адресом частота выведена из настройки ограничителя, перечень расширений — из меток метрики за вычетом audio, предел переименован в «частоту опроса карточки»
Паспорт, модель угроз и архитектура остались бы описывать убранные адреса, и плана правки на них не было заведены три шага плана

Второго чекпоинта не было, и это осознанно: ни одна из пяти находок не меняла решения, принятого человеком, — все они приводили спеки и план в согласие с уже принятым.

Что осталось названным, но не закрытым: имя капабилити archive совпадает словом с каталогом заархивированных change и с тем, как паспорт зовёт весь сервис. Имя оставлено — каталоги разные, слово в проекте своё.

Границы покрытия стадии

  • Метка large, режим «по графу»; проходов три, все вернулись, потолок не срабатывал ни у одного — rubric вывел 8 из 8 построенных, architecture упёрся в свои 3 и объявил это, specs потолка не имеет на этой метке.
  • Кода не существует: ничего не запускалось, кроме openspec validate --strict. Гейт на этой стадии не гоняется по построению.
  • Команды сборки карты проекта в Taskfile.yml нет — архитектурный проход собирал инвентарь понятий грепом, и такой инвентарь беднее подготовленного.
  • docs/adr/ и docs/research/ прогоном не открывались: процессные документы. Расхождение изменения с записанным решением этой стадией не ловится — это работа сверки документации.
  • Альтернативной реализации, с которой можно сдиффить решения, у конвейера нет: проход независимой реализации упразднён решением о стоимости.
  • Что будет с этим на живых данных, не проверял никто: данных нет, стадия — стройка.