Перейти к содержанию

ADR-0004 · Терминал без связи: норма, а не деградация#

Статус:    принят · 2026-09-18
Метод:     D-06 v1.0 · шаблон ADR v1.2
Участники: сопровождение (3 человека), Каменев — руководитель операционного блока

Учебная запись: часть прогона E-03, система вымышлена. Форма и рассуждение настоящие.

Контекст#

Вход — 00-context.md. 108 пунктов из 900 (12 %) теряют связь суммарно до 40 минут в сутки, в сезон до двух часов [замер].

Два применения, а не одно#

D-06 группирует функции по классу важности, инварианту и зависимости. Зависимость одна — ядро; класс важности один; инварианты разные, и это делит функции надвое.

Применение Функции Инвариант Кто его держит
Первое Выдача И2 · выдача происходит один раз Физический мир. Коробка одна; отдать её дважды нельзя, сколько бы раз ни нажали кнопку
Второе Приёмка, возврат И1 · у посылки одно место и один ответственный Никто. Проверка «эта посылка предназначена этому пункту» существует только в ядре

Третий вопрос D-06 решил здесь больше остальных вместе взятых, и ответ у него физический. Выдача офлайн безопасна не потому, что мы что-то построили, а потому, что инвариант закрывает полка. Приёмка офлайн опасна потому, что её инвариант не закрывает никто — и именно из неё система производит собственные расхождения, те самые 0,4 %.

Семь вопросов#

Вопрос Ответ
Какая функция и какая зависимость может отказать отдельно Приём, выдача, возврат на пункте; зависимость — ядро учёта
Что обещано пользователю сейчас Ничего явно. Терминал молча принимает и выдаёт, данные уезжают позже [орг]
Какой инвариант держит функция и закрывается ли где-то ещё См. таблицу выше — разошлись [требования]
Какие суррогаты существуют Локальный снимок: что этот пункт держит на момент последней связи. Существует уже сегодня [схема]
Класс важности относительно соседних Высший: пункт без приёма и выдачи не работает, 1 400 монтажников не получают наряды [продукт]
Как система узнаёт об отказе — и совпадает ли это с тем, что видит потребитель Терминал знает. Ядро — нет: со стороны ядра молчащий пункт неотличим от пункта без операций [схема]
Что станет с нагрузкой на зависимость при деградации Ничего: суррогат локальный, обращений к ядру не добавляется [схема]

Дисквалификаторы#

Из пяти сработали три, один перевернулся, один не сработал.

Условие Что вышло
Деградация нарушает инвариант; молчаливая подмена там, где по данным принимают решение Сработал. Кладовщик, принимая посылку офлайн, решает, куда её положить и кому она предназначена. Данных для этого решения у него нет, и молчание превращает приёмку в обман. Отсекает нулевой вариант — то, как работает система сегодня
Путь деградации не исполняется регулярно Перевернулся. Путь исполняется ежедневно на 108 пунктах. Дисквалификатор написан против редких путей и здесь не просто не срабатывает — он указывает в обратную сторону, см. замечание
Суррогат добывается через отказавшую зависимость Не сработал: локальный снимок лежит на терминале и ядра не требует
Система не умеет заметить отказ Сработал, и в обе стороны. Терминал отказ видит. Ядро — нет, а решение о разборе принимает ядро. Дисквалифицирован способ обнаружения: пока со стороны ядра молчащий пункт неотличим от пункта без работы, любой вариант останется невключённым
У режима нет выхода Сработал частично. Условие снятия есть — связь восстановилась. Владельца разбора непроверенных операций нет

Рассмотренные варианты#

Матрица для второго применения — приёмка и возврат. Первое применение матрицы не требует: инвариант держит физика, и вариантов, кроме «работать как работает», нет.

Ось Что записывать 0 · как сейчас Явный отказ С пометкой, выдачу блокировать С пометкой, без блокировки
Сохранность инварианта Держится ли И1 Нет — приёмка вслепую и производит расхождения Да Да — непроверенная посылка не уходит дальше Нет: выдать можно то, что принято ошибочно
Что видит пользователь и понимает ли Дословно Ничего, как в норме «Нет связи. Приём невозможен» «Нет связи, данные на 09:14. Принято без проверки, выдача до восстановления связи заблокирована» «Принято без проверки»
Нагрузка на отказавшую зависимость Прирост обращений 0 0 0 0
Стоимость построения Что строим 0 Экран отказа Статус посылки, экран, блокировка выдачи Статус и экран
Стоимость владения путём Постоянная цена 0 Простой пункта до двух часов в сезон Разбор непроверенных операций: владелец и регламент Разбор без блокировки — то есть постфактум
Обратимость: как выходим Условие и владелец Неприменимо Связь восстановилась Связь восстановилась, ядро подтвердило, статус снят Связь восстановилась

Что стоит блокировка выдачи. Офлайн длится 4,8 % рабочего времени на 12 % пунктов, то есть задевает 0,57 % приёмок [расчёт]. Из них блокировка мешает только тем, за чьей посылкой пришли в то же окно, — доля, которую мы не мерили, но верхняя граница уже мала. Явный отказ, для сравнения, останавливает приём целиком на всё окно.

Решение#

Офлайн описан как нормальный режим работы, а не как деградация — см. замечание к методу. Формы:

  1. Выдача офлайн разрешена без ограничений. Терминал показывает полосу «Нет связи с ядром, данные на 09:14». Инвариант И2 держит полка.
  2. Приёмка и возврат офлайн разрешены с пометкой. Посылка получает статус «принята без проверки»; в этом статусе выдача заблокирована до подтверждения ядром. Экран кладовщика: «Принято без проверки. Выдача до восстановления связи заблокирована».
  3. Ядро получает сигнал «пункт не выходил на связь N минут». Без него молчащий пункт неотличим от пункта без работы, и дисквалификатор о способе обнаружения остаётся несnятым. Значение N и то, чем его мерить, — на этапе 6.
  4. Владелец разбора непроверенных операций — диспетчер склада-куратора. Регламент: подтверждённые ядром статусы снимаются автоматически; не подтверждённые за смену уходят в разбор поимённо.
  5. Регулярное исполнение пути не строится отдельно. Обязательная строка записи D-06 выполняется сама: путь исполняется ежедневно на 108 пунктах. Это единственный известный случай, когда она не требует работы.

Подтверждение со стороны продукта: Каменев, руководитель операционного блока, — обещание «принимаем всегда, выдаём только проверенное».

Обоснование#

Решил третий вопрос, а не матрица. Как только выяснилось, что И2 держит физический мир, а И1 — никто, две функции разошлись, и для одной из них вариантов не осталось вовсе. Матрица понадобилась только для второй.

Нулевой вариант отсечён дисквалификатором, а не проигрышем по осям — и это единственный вариант, который сегодня работает в проде. Система одиннадцать лет принимает вслепую и молчит об этом.

Блокировка выдачи выбрана против варианта без блокировки по единственной оси, где они расходятся: сохранность инварианта. Цена — 0,57 % приёмок в худшем случае; цена отказа от неё — сохранить ровно тот механизм, который производит расхождения.

Последствия#

Отрицательные:

  • Появляется статус, которого не было, и он виден кладовщику. Одиннадцать лет терминал не различал проверенное и непроверенное; обучение 1 900 терминалов и их пользователей в цену решения входит.
  • Разбор непроверенных операций — постоянная работа, которой сегодня нет ни у кого. Объём неизвестен: сколько операций уходит в офлайн, не меряли.
  • Сигнал «пункт молчит» строится с нуля. Предметных метрик нет ни одной; это будет первая.
  • 0,57 % приёмок получают задержку до двух часов в худшем случае, и эта доля сезонная — в ноябре выше.
  • Блокировка выдачи ляжет на кладовщика, а не на систему: получатель стоит перед ним, а коробка есть. Регламент разговора в решение не входит, но без него решение не работает.

Положительные: механизм, производивший расхождения, назван и перекрыт; обещание впервые сформулировано словами и подтверждено именем; путь исполняется ежедневно и потому не может отказать от неиспользования.

Замечание к методу: у D-06 есть условие пересмотра без парного дисквалификатора#

Раздел 7 D-06 содержит условие: «Режим включался чаще, чем ожидалось. Частое срабатывание означает, что это не деградация, а нормальный режим работы, и его надо описывать как норму».

Здесь это условие выполнено до принятия решения, а не через год наблюдений: офлайн случается ежедневно и известен замером на входе. Документ применяется к тому, что по его же правилу не является его предметом.

Дисквалификатора, соответствующего этому условию пересмотра, у D-06 нет. Условие пересмотра срабатывает после, дисквалификатор — до; здесь нужен второй, а есть только первый.

И при этом документ оказался полезен, отведя себя. Он дал:

Что дал Откуда
Разделение на два применения с разными инвариантами Правило «что считать одной функцией»
Асимметрию выдачи и приёмки Третий вопрос — кто держит инвариант
Отсечение того, как система работает сегодня Дисквалификатор о молчаливой подмене
Требование сигнала со стороны ядра Дисквалификатор о способе обнаружения
Владельца разбора Дисквалификатор о выходе из режима

Это не «применим и бесполезен» — режим, которого ждали от D-04 и который ни разу не повторился. Это обратное: применим, отводит себя по собственному правилу и всё равно даёт результат. Как это записать в метод — вопрос ревизии; здесь зафиксировано наблюдение.

Условия пересмотра#

  • Доля офлайна выросла или упала на порядок — 40 минут в сутки перестали быть верхней границей.
  • Появился способ проверить принадлежность посылки пункту без ядра — например, признак в самом штрихкоде; тогда приёмка офлайн перестаёт быть слепой.
  • Разбор непроверенных операций перестал выполняться в срок — решение просрочено, а не действует.
  • Сигнал «пункт молчит» не ловит случай, когда терминал отвечает, а операции не уходят, — это серый отказ, и обнаружение придётся строить со стороны ядра иначе.
  • Блокировка выдачи стала задевать заметно больше 0,57 % приёмок.
  • Класс важности приёмки изменился относительно выдачи.

Самая дорогая будущая граница#

Граница между тем, что терминал знает сам, и тем, что знает только ядро. Сегодня она проходит по одному признаку — принадлежности посылки пункту. Каждая новая проверка, которую захотят добавить в приёмку, попадёт на ту же линию и потребует того же выбора: блокировать, помечать или принимать вслепую. Линия задана здесь и один раз; переносить её потом означает менять поведение 1 900 терминалов, обновляющихся неделями.

Связанные ADR#

Зависит от: ADR-0002 — локальная очередь терминала объявлена копией со сроком жизни 48 часов. Зависимые: цели и измеритель (этап 6) — оттуда придут значение N для сигнала «пункт молчит» и доля офлайновых операций.