E-01 · Что вскрыл прогон#
Все восемнадцать находок закрыты 2026-09-16 — см. итог ревизии и план. Три из них (2, 12, 13) план пропустил: они попали в правки уже при исполнении. Файл сохраняется как есть — он показывает, что именно прогон обнаружил и в каком порядке.
Копится по ходу, применяется на этапе 6. Правки в шаблоны не вносятся по ходу: иначе документы будут меняться под уже написанные ADR, и прогон перестанет быть проверкой.
После этапа 2 (D-01 → ADR-0001)#
| № | Находка | Где чинить |
|---|---|---|
| 1 | У гринфилда не существует пометки [замер] — измерять нечего. Пришлось объявить [расчёт W1] прямо в ADR. Словарь пометок молча предполагал существующую систему |
00-template.md, правило о пометках |
| 2 | Все сработавшие дисквалификаторы — организационные, ни одного технического. В списке D-01 они перемешаны; на обычной системе технические не сработали вовсе | D-01, порядок дисквалификаторов |
| 3 | [нет данных] не заблокировало решение. D-01 говорит, что пустая ячейка сообщает, какой замер нужен «прежде чем решать». Но ось «стоимость владения» не различала оставшиеся варианты — и пустота оказалась безвредной. Нужна оговорка: блокирует только та пустая ячейка, что стоит в оси, различающей кандидатов |
00-template.md |
| 4 | Реестр ограничений перерос порог сразу. Правило D-01 обещало вынос «когда записей больше десятка»; четыре появились после первого же ADR. Порог завышен примерно втрое | D-01, раздел 4 |
| 5 | Пришлось явно написать, чего решение не решает. Выбор хранилища не закрывает 8 000 чтений/с — это уровень W5. В D-01 нет строки о границе решения, и без неё соблазн закрыть чтения выбором БД остаётся | D-01, шапка |
| 6 | Ничья возникла там, где её не ждали. PostgreSQL и MySQL 8.0 совпали по обеим решающим осям (SKIP LOCKED есть у обоих [док]). Матрица отработала правильно — показала отсутствие различий, — но выбор сделала эвристика. Это не дефект: так и задумано |
— |
После этапа 3 (D-02 → ADR-0002)#
| № | Находка | Где чинить |
|---|---|---|
| 7 | Раздел 1 D-02 целиком построен на истории, которой у гринфилда нет. Три вопроса из семи структурно [нет данных] — не по небрежности, а потому, что репозитория и трекера не существует. Эвристика «связность изменений считается за час по трекеру» даёт невыполнимую инструкцию, а не отсрочку |
D-02, раздел 1 и эвристики |
| 8 | Дисквалификация оставила один вариант — матрица выродилась в одну колонку. Шаблон не говорит, что делать: заполнять нечего, а пустой раздел выглядит как лень. Понадобилась оговорка прямо в ADR | 00-template.md, раздел 3 |
| 9 | Форма разреза «по профилю нагрузки» путается с решением о кэше. Разница чтений и записей в 27× выглядит как основание для границы сервиса, но путь чтения не имеет своего языка, инвариантов и владельца данных — это проекция, а не ограниченный контекст | D-02, раздел 4 |
| 10 | Самый ценный выход ADR оказался побочным: названа самая дорогая будущая граница (Инвентарь ↔ Заказы, по ней идёт транзакция подтверждения). Ни в D-02, ни в шаблоне ADR такого поля нет, а через год это ровно то, что нужно знать | D-02, раздел 6 или 01-adr-template.md |
Отрицательный результат, важный для метода. Гипотеза перед этапом была: «документ поддастся соблазну что-нибудь разрезать». Не поддался — три дисквалификатора сработали и отсекли саму идею разреза, ровно как D-02 и обещает («последние три отсекают саму идею разрезать сейчас»). Но выяснилось это не благодаря сравнению, а вместо него.
После этапа 4 (D-04 → ADR-0003)#
Самый урожайный этап: четыре находки, и две из них — противоречия внутри уже написанного.
| № | Находка | Где чинить |
|---|---|---|
| 11 | Условие применимости D-04 сформулировано неверно. Документ говорит «для каждого процесса, пересекающего границы сервисов». Сервисов у нас нет, но процесс пересекает границу внешнего платёжного провайдера — а там общая транзакция недостижима принципиально. Правильное условие: процесс пересекает границу, за которой нет общей транзакции, и своя это граница или чужая — неважно | D-04, шапка и эвристика «отложить» |
| 12 | Оси согласованности не хватает третьего значения. Есть «атомарная» и «итоговая», а встретился третий случай: атомарность требуется бизнесом и недостижима технически (деньги в чужой системе). Записать пришлось как «итоговую», но это не то же самое: из недостижимости следуют обязательства, которых у обычной итоговой согласованности нет — состояние неизвестен и обязательная сверка |
D-04, раздел 1 и 3 |
| 13 | Нулевой вариант в перечисляемом типе всё-таки есть. 00-template.md v3.0 утверждает: «Не бывает: в какой-то ячейке мы находимся всегда». Контрпример нашёлся сразу — участок «выбор места → резерв» это локальная транзакция в одном модуле, он не попадает в пространство восьми ячеек вообще. Правило, записанное четыре дня назад по рассуждению, опровергнуто первым же применением |
00-template.md, таблица трёх типов |
| 14 | Один рабочий процесс распался на два решения. Область применения — не «процесс» как его называет продукт, а участок между границами. Документ нигде не говорит, как процесс делить перед применением | D-04, раздел 1 |
Что сработало ровно как задумано. Эвристика «начинать с согласованности, а не со связи» вывела на главный вопрос первым же ходом — и заодно обнажила, что документ этого случая не описывает. Из трёх координат две оказались заданы извне (инвариантом и поведением провайдера), выбирали только координацию. Это подтверждает устройство третьего типа: координаты определяют, а не выбирают.
После этапа 5 (D-03 → ADR-0004)#
| № | Находка | Где чинить |
|---|---|---|
| 15 | D-03 противоречит сам себе на гринфилде. Дисквалификатор: «узкое место не подтверждено замером» — решение принимать нельзя. Эвристика: «"нет данных" здесь не повод откладывать, включить умолчание и померить». Оба про одну ситуацию, выводы противоположные | D-03, дисквалификаторы и эвристики |
| 16 | В таблице отклонений нет главной развилки читающего кэша: инвалидация против короткого TTL. Отклонения D-03 описывают стратегии записи и размещение. Для данных, меняющихся 300 раз в секунду, «удаление ключа при записи» — не стратегия, а отказ кэша работать: ключ живёт 3 мс | D-03, раздел 3 |
| 17 | Дисквалификатор выдавил наружу решение, которого в наборе нет. «Система не переживает отказа кэша» → нужна деградация. Проектирование деградации продуктовое, необратимое одним коммитом и принимается на W7 — то есть это отдельное полное решение, а не строка в короткой записи | новый документ решения, W7 |
| 18 | Короткая форма и короткая запись — разные вещи. Решение по короткой форме оказалось несущим, и пять строк не вместили обоснования отказа от умолчания. Правило «если запись разрослась, проверьте, не полная ли это форма» дало ложный сигнал: форма верна, вырос не метод, а обоснование | 00-template.md, 01-adr-template.md |
Сквозная закономерность: документы двоичны там, где реальность троична#
Проявилось в трёх документах из четырёх, каждый раз независимо:
| Документ | Два значения в документе | Третье, встреченное в прогоне |
|---|---|---|
D-01 |
[замер] · [нет данных] |
[расчёт] — выведено арифметически, слабее замера, сильнее догадки |
D-04 |
атомарная · итоговая | требуется, но недостижима — с обязательной сверкой |
D-03 |
узкое место подтверждено · не подтверждено | выведено расчётом: 8 000 чтений/с против одного узла — не догадка и не замер |
Три независимых случая одной формы — это не совпадение, а системная черта: при написании документов я подразумевал работающую систему, где всё измеримо. Лечится не тремя заплатками, а одним правилом о трёх степенях достоверности факта. Кандидат на правку мастер-шаблона на этапе 6.
Принятая позиция: стадия проекта — отдельное решение, а не ветка внутри#
Записана 2026-09-16, до этапа 5. Определяет, как чинить находки 1 и 7 на этапе 6.
Позиция. Если на разных стадиях проекта решение принимается по-разному, это разные решения в разных документах — а не условные ветки внутри одного. Условная ветка размывает ответственность документа: читателю приходится сначала определить, в какой он ветке, а способа определить в документе нет.
Прогон подтвердил это раньше, чем позиция была сформулирована. Находка 7: раздел 1 D-02 на гринфилде не «работает наполовину», он не работает вовсе — измерять связность изменений не по чему. Ветка «если системы ещё нет, пропустите вопросы 1, 3 и 7» превратила бы документ в такой, где половина вопросов помечена «(если система уже работает)» — классический способ сгнить.
Различаются не ответы, а метод#
| Границы на гринфилде | Границы работающей системы | |
|---|---|---|
| Главный вопрос | Какие границы заложить | Где резать |
| Откуда факты | Предсказание по требованиям и языку | Измерение по истории изменений |
| Решающий дисквалификатор | Нет наблюдаемости и владельцев | Разрыв атомарной операции, общая таблица |
| Эвристика при нехватке данных | Модульный монолит — данных не будет ещё полгода | Посчитать за час по трекеру |
| Цена ошибки | Дни: перенос модуля | Квартал: перенос между сервисами |
Это не одно решение с разными числами. Это разные вопросы.
Разделяющий признак — чтобы не расплодить документы#
Дробить по стадиям всё подряд нельзя: четыре решения на три стадии дадут двенадцать документов. Признак разделения:
Разделять, если меняется источник фактов, дисквалификаторы или эвристики. Не разделять, если меняются только значения в ячейках.
Проверка на том, что уже есть в прогоне:
| Документ | На гринфилде | Вердикт |
|---|---|---|
D-01 хранилище |
Метод тот же; понадобился только свой словарь пометок — [расчёт W1] вместо [замер] |
Не разделять |
D-02 границы |
Нет источника фактов, другие дисквалификаторы, эвристика даёт невыполнимую инструкцию | Разделять |
Признак различил оба случая правильно, не будучи под них подогнан.
Стадий, похоже, три#
| Стадия | Чем отличается для решений |
|---|---|
| Гринфилд | Фактов нет, они предсказываются. Пометки [расчёт], не [замер] |
| Работающая система | Факты измеряются. Появляется история, появляется «посчитать за час» |
| Система под изменением | Есть работающая система и обязательство её не сломать: миграция, обратная совместимость, окно перехода, откат |
Третьей стадии в decisions/ нет вовсе, а именно на ней принимается большинство решений в живых проектах.
Как называть#
Не D-02a / D-02b. Буквенный суффикс намекает, что один документ — вариант другого, и провоцирует прочесть только один. Отдельные номера плюс строка «Не путать с» в шапке, рядом с уже существующей «Известно также как»: первая ловит синонимы, вторая — соседей, которых легко перепутать.
Оговорка#
Два этапа назад я возражал против расширения набора вширь. Здесь противоречия нет: это не новые решения, а разделение существующих там, где метод действительно разный, и разделяющий признак держит рост ограниченным. Но правило стоит проверить на E-02: если на другом кейсе оно начнёт делить всё подряд, признак слишком слабый.
Наблюдение, не требующее правки#
Три ответа из четырёх оказались скучными: PostgreSQL, модульный монолит, кэш в процессе. Это правильный результат. Метод, который на обычной системе даёт захватывающие ответы, сломан — он подталкивает к экзотике там, где её не нужно. Ценность записи не в ответе, а в том, что отвергнутые варианты получили причины и условия пересмотра, а граница решения названа явно. К третьему этапу видно и другое: скучный ответ получен за час вместо недели архитектурных споров — и с записанными условиями, при которых он перестанет быть верным.
Урок о проверках, не о документе#
Первый негативный тест новой проверки ADR не сработал, и это выглядело как «проверка не ловит ошибку». На деле не совпали пробелы в sed, и подсадить ошибку не удалось — файл остался нетронутым. Тот же класс ошибки, что две ложные метрики ревизии №2: тест, который не сработал, может означать сломанный тест, а не рабочий код. Правило: подсадка ошибки обязана сама себя проверять (assert, что файл изменился).