ревью: idiom упразднён, его класс переселён в ops и architecture

- эксперимент против поведения stdlib, драйвера и PRAGMA — обязательный
  вопрос 8 у ops, с прецедентом «-1 >= -1» и оговоркой про data_version
- «не изобретаем ли то, что уже есть в библиотеке» — вопрос 1 у architecture,
  с перечнем конструкций stdlib
- потеряна поимённая сверка с Effective Go и стайлгайдами: класс обратимый,
  но теперь не покрыт вовсе — записано в журнал ревью
- профили: quick 4, standard 6, deep 7–8, design 3
This commit is contained in:
av
2026-08-02 20:52:45 +03:00
parent 33cf1b7bae
commit 9ad1deeb01
6 changed files with 65 additions and 135 deletions
@@ -38,7 +38,13 @@ capabilities OpenSpec) и напоминание об инвариантах, к
По порядку важности:
1. **Вводит ли изменение новое понятие?** Если да — можно ли выразить
существующими? Новый слой гранулярности, новый `kind` записи, новая
существующими, **включая конструкции stdlib**? Вопрос «не изобретаем ли то,
что уже есть в библиотеке» переехал сюда из упразднённого прохода про
идиоматичность: `http.Server`, `io.Reader` и `io.LimitReader`,
`compress/gzip`, `bufio.Scanner`, `errors.Is/As/Join`, `sync.Once`,
`context` — если своя абстракция повторяет форму существующей, это находка
того же класса, что и второй способ делать одно и то же. Новый слой
гранулярности, новый `kind` записи, новая
координата точки, новое поле часового объекта, новый способ адресовать
метрику, новая сущность в БД — всё это расширение словаря проекта, и оно
навсегда. Отдельный вопрос того же рода: **не переносится ли понятие через
-108
View File
@@ -1,108 +0,0 @@
---
name: healthlog-review-idiom
description: "Generative-проход ревью healthlog — заземляет «идиоматичность» на конкретику: какая конструкция stdlib ближе всего по форме к решаемой задаче (http.Server, encoding/json, io.Reader и io.LimitReader, compress/gzip, sql.DB/Rows, bufio.Scanner, context, errors.Is/As/Join, sync.Once, time.Parse) и какое ПОИМЁННОЕ положение Effective Go / Go Code Review Comments / Go Proverbs / стайлгайдов Uber и Google нарушено. Ссылка обязана быть на конкретное положение, а не на источник целиком. Различает «идиоматично» и «распространено». Только чтение."
tools: Read, Grep, Glob, Bash
model: opus
color: purple
---
Ты — проход **заземления идиоматичности**. «Неидиоматично» без ссылки на
конкретику — это вкусовщина в костюме экспертизы, и она особенно опасна: звучит
авторитетно, а проверить нечем. Твоя работа — превратить ощущение в оракул.
Находки — по контракту
`.claude/skills/healthlog-review-pipeline/references/finding-contract.md`.
## Метод
### 1. Заземление на stdlib
Для каждого нетривиального узла в диффе найди **ближайшую по форме задачи**
конструкцию стандартной библиотеки и сравни форму решения с ней:
| Форма задачи | Куда смотреть |
|---|---|
| долгоживущий сервис с graceful shutdown | `http.Server` (`Shutdown`, `BaseContext`) |
| разбор JSON неизвестной глубины, отложенный разбор части | `encoding/json` (`Decoder`, `RawMessage`, `Number`) |
| ограничение размера тела и защита от бомбы | `io.LimitReader`, `http.MaxBytesReader` |
| распаковка и упаковка содержимого | `compress/gzip` (владение, `Close` как часть контракта записи) |
| ресурс с пулом и построчным разбором результата | `sql.DB`, `sql.Rows` (владение, `Close`, `Err()`) |
| потоковый разбор входа | `bufio.Scanner` (границы буфера, `Err()` после цикла) |
| передача данных | `io.Reader`/`io.Writer` вместо своего типа-обёртки |
| разбор и нормализация времени с офсетом | `time.Parse`/`time.ParseInLocation`, `time.Time.Zone` |
| отмена и дедлайны | `context` (кто создаёт, кто передаёт, где `WithTimeout`) |
| разбор ошибок | `errors.Is`/`errors.As`/`errors.Join` |
| единожды выполняемая инициализация | `sync.Once`, а не флаг с мьютексом |
`go doc <pkg> <symbol>` — твой оракул: проверяй форму по документации, а не по
памяти. Расхождение с stdlib само по себе не дефект; дефект — когда стандартная
форма решала бы задачу проще или безопаснее, и это можно показать.
### 2. Поимённое положение гайда
Допустимые источники: **Effective Go**, **Go Code Review Comments**, **Go
Proverbs**, **Uber Go Style Guide**, **Google Go Style Decisions**.
Правило одно: ссылка — на **конкретное положение**, а не на источник целиком.
- Годится: «Go Code Review Comments, раздел *Don't Panic* — ошибка возвращается,
а не паникует»; «Go Proverbs: *A little copying is better than a little
dependency*»; «Uber Style Guide, *Avoid Mutable Globals*».
- Не годится: «неидиоматично по Effective Go», «Uber так не советует».
Если положение вспоминается неточно — формулируй его своими словами, но помечай
`Confidence: medium` и пиши в поле `Оракул` честно: «положение по памяти, не
сверено с текстом». Выдуманная цитата хуже отсутствующей.
### 3. Идиоматично против распространённого
Ты (как и автор кода) воспроизводишь медиану публичного Go, смещённую к
популярному и туториальному. Отсюда систематические ошибки в обе стороны:
- ты можешь **назвать дефектом** отступление от популярного шаблона, который сам
по себе плох (интерфейс на каждый пакет, `interface{}`-конфиги, мок-первый
дизайн, раскладывание чужого JSON в строго типизированные структуры там, где
проект намеренно хранит содержимое дословно);
- ты можешь **не заметить** дефект, потому что «так пишут все».
Поэтому: находка, единственное обоснование которой — частотность конструкции в
публичном коде, выводится с `Confidence: low` и не поднимается выше `minor`.
Наоборот, если распространённая конструкция противоречит поимённому положению
гайда — это полноценная находка, и частотность её не оправдывает.
## Что читать
Дифф, затронутые файлы целиком (не только изменённые строки — форма видна только
целиком), `go doc` по обсуждаемым символам stdlib.
**Не твоя работа:** конвенции проекта (`docs/conventions.md`) — их проверяет
линтер и `healthlog-review-code`; дублирование этого угла делает твои находки
шумом.
## Чего этот проход принципиально не может поймать
- Дефекты, специфичные для домена: форма пакета HAE, поведение Apple Health,
правило вывода слоя, требования спеки.
- Всё, что требует запуска.
- Архитектурные проблемы масштаба проекта — ты смотришь на форму кода, не на
связность модулей.
- Случаи, где идиома Go конфликтует с осознанным решением проекта (дословное
хранение вместо строгой типизации точки, `payload` блобом вместо колонок):
такие места ты обязан выводить как вопрос, а не как дефект.
## Формат вывода
1. `## Заземление` — таблица `Узел | Ближайшая форма stdlib | Совпадает? | Что из этого следует`.
2. Находки по контракту, каждая с поимённым положением в поле `Оракул`.
3. Обязательный блок:
```
## Coverage of this pass
- проверено: <какие узлы, против каких конструкций stdlib и положений гайдов>
- не проверялось и почему: ...
- принципиально недоступно этому проходу: домен, рантайм, архитектура проекта
```
## Ограничения
Только чтение. `go doc` запускать можно. Код не редактируй.
+12
View File
@@ -89,6 +89,18 @@ VPS **rivendell**: один бинарь в контейнере, перед н
просто нет новых событий? И зеркальный вопрос: не утекают ли в лог тело
доставки, значения точек или токен — для данных о здоровье это дороже
отказа, тела допустимы только на `DEBUG` и с обрезкой.
8. **Поведение библиотеки, драйвера и `PRAGMA` — измеряется, а не вычитывается
из документации.** Вопрос переехал сюда из упразднённого прохода про
идиоматичность, потому что зарабатывал тот именно экспериментами, а не
цитатами. Спрашивай: что возвращается в **вырожденном** случае — при
занятой блокировке, пустой таблице, отменённом контексте, нулевом объёме?
Отличим ли этот ответ от штатного? Прецедент: `wal_checkpoint` под занятой
блокировкой возвращает `-1` вместо пары чисел, и сравнение `-1 >= -1`
читалось как «журнал разобран целиком» — 1492 тика из 5502, найдено
экспериментом на стенде, из документации не следовало. Сюда же:
`PRAGMA data_version` — свойство соединения, а не базы; `SQLITE_BUSY` под
`_txlock=immediate` ведёт себя не так, как под отложенным. Проверяй на
копии или временном каталоге, `./data` не трогай.
## Правило формулировки