язык: объявлена граница правила

- область правила — от его заголовка до следующего заголовка любого уровня;
  метка открывает блок, хвост после ПОЧЕМУ — продолжение обоснования, а
  таблица после модальной метки — часть нормы
- проверка «заглавных модальных слов вне правил нет» стала реализуемой:
  прозой считается то, что лежит вне областей правил
- нормы, сидевшие в хвостах, подняты в блок нормы: заведены SLOG-25.4 и
  GERR-26.3, у GTIM-12 «базовый слой» заменён на TIME-12
This commit is contained in:
av
2026-07-26 15:10:59 +03:00
parent 4943bf1dd2
commit df8c58671f
6 changed files with 95 additions and 57 deletions
+11 -8
View File
@@ -344,8 +344,9 @@ HTTP-клиентов, файловой системы, внешних SDK.
| № | Где перехвачена паника | Что дальше |
|---|---|---|
| GERR-26.1 | обработчик HTTP-запроса | ответ 500, если он ещё не начат; процесс и прочие запросы не затрагиваются |
| GERR-26.1 | обработчик HTTP-запроса, паника любая, кроме сигнала намеренного прерывания | ответ 500, если он ещё не начат; процесс и прочие запросы не затрагиваются |
| GERR-26.2 | итерация цикла обработки — бот, воркер | цикл продолжается со следующего элемента, упавший элемент повторно не берётся |
| GERR-26.3 | обработчик HTTP-запроса, паника — сигнал намеренного прерывания (`http.ErrAbortHandler`) | значение пробрасывается дальше, ответ не подменяется |
**ПОЧЕМУ.** Паника внутри обработки одного элемента почти всегда говорит о
баге в работе с данными этого элемента, а не о порче общего состояния, —
@@ -356,10 +357,11 @@ HTTP-клиентов, файловой системы, внешних SDK.
обязательным (GERR-22): неперехваченная паника в любой горутине завершает весь
процесс.
Продолжать, не исключив упавший элемент, нельзя: детерминированная паника
даёт бесконечный цикл — тот же элемент, тот же стек, залитый лог и нулевой
прогресс. Это классический poison message, и лекарство берём то же, что
принято в очередях: элемент выводится из оборота, а не берётся снова. У
Исключение упавшего элемента в GERR-26.2 — не осторожность, а условие
прогресса: детерминированная паника даёт бесконечный цикл — тот же элемент,
тот же стек, залитый лог и нулевой прогресс. Это классический poison message,
и лекарство здесь то же, что принято в очередях: элемент выводится из
оборота, а не берётся снова. У
цикла, который и так подтверждает прогресс — сдвигает офсет, помечает
строку состоянием, — механизм для этого уже есть, заводить отдельный не
нужно.
@@ -369,9 +371,10 @@ HTTP-клиентов, файловой системы, внешних SDK.
клиент получит обрывок с кодом 200. Отсюда же общее предпочтение собирать
ответ целиком до записи там, где это возможно.
Из GERR-26.1 есть одно исключение: `http.ErrAbortHandler`сигнал «прервать
обработку намеренно», и recover-обёртка пробрасывает его дальше, а не
превращает в 500. Так поступают и стандартные обёртки вроде chi.
Отдельная строка GERR-26.3 нужна потому, что `http.ErrAbortHandler`не
отказ, а сигнал «прервать обработку намеренно»: подмена его на 500 превратила
бы штатный разрыв в ложную ошибку в логе и в метриках. Так поступают и
стандартные обёртки вроде chi.
### GERR-24. Независимые ошибки собираются `errors.Join`
+6 -3
View File
@@ -337,6 +337,7 @@ ctx = logctx.With(ctx, log) // достаём логгер из ctx в кажд
| SLOG-25.1 | штатный конфликт состояния или некорректный ввод | пользователю, он уже получил ответ | `DEBUG` |
| SLOG-25.2 | расхождение производного или учётного состояния, первичные данные целы | владельцу, «может стать проблемой» | `WARN` |
| SLOG-25.3 | сбой БД, ФС, недоступность зависимости | владельцу, в разбор | `ERROR` |
| SLOG-25.4 | класса нет: отказ в классификацию не заведён | владельцу, как пропуск в классификации | `ERROR` с отметкой о непокрытом классе |
**ПОЧЕМУ.** Это применение SLOG-8 к отказам: пользователь уже увидел причину на
экране — владельцу разбирать нечего; целостность первичных данных отделяет
@@ -349,9 +350,11 @@ ctx = logctx.With(ctx, log) // достаём логгер из ctx в кажд
таблицу не входит: это не доменный отказ, и логирует его recover-граница
вместе со стеком (конвенция `errors`). Искать его класс здесь не нужно.
Мимо таблицы идёт и доменная ошибка, которой нет в маппинге: класса у неё
нет, потому что её просто забыли завести. Она логируется `ERROR` с
признаком непокрытой (`GERR-25`).
Строка SLOG-25.4 говорит не о классе отказа, а о пропуске в самой
классификации: ошибку забыли завести в маппинге. `ERROR` здесь — громкость,
по которой пропуск находят фильтром, а не оценка тяжести отказа; саму отметку
о непокрытом классе ставит трансляция ошибки (`GERR-25` в конвенции
`errors`).
### SLOG-26. Тот же отказ в асинхронной стадии — уровнем выше
+2 -2
View File
@@ -180,8 +180,8 @@ func utcTime(_ []string, a slog.Attr) slog.Attr {
текущего значения настройки: смена зоны задним числом сдвигает границы
суток у того, что давно посчитано и сохранено.
Календарные вычисления бизнес-логики берут зону явно — как описано в
базовом слое.
Явную зону в календарных вычислениях требует TIME-12 — это его правило, а не
второе такое же здесь.
## Связано