httpapi: точки метрики за период отдаются одним запросом
- `GET /api/v1/metrics/{name}?from&to&layer` — ряд точек за период; конверт
объявляет слой, измеренный род, его применимость к отданному ряду и границу
окна измерения, а сам ряд собирается из одного слоя, выбранного по охвату
точек внутри периода
- use-case вынесен в `internal/points`, чтение — одним входом `store.ReadSeries`
под одной транзакцией; правило выбора слоя остаётся в домене и приходит в
хранилище колбэком
- `writeJSON` перестал экранировать HTML-символы и перестал глушить отказ
записи: дословность содержимого точки иначе не удерживается, а оборванное
тело уходило под видом успешного `200`
This commit is contained in:
@@ -142,6 +142,13 @@
|
||||
|
||||
**Перестали проверять сознательно.**
|
||||
|
||||
- **Шаг покрытия диффа гейт не красит.** `CLAUDE.md` объявляет, что непокрытая
|
||||
изменённая строка красит гейт безусловно; `scripts/diff-coverage.py` всегда
|
||||
возвращает `0`, и шаг печатает `OK` при любом покрытии. То есть «гейт зелёный»
|
||||
не означает «покрытие диффа полное», и разбор непокрытых строк остаётся
|
||||
человеку или проходу. Найдено проходом `gate` 2026-08-04, подтверждено
|
||||
триажем; чинить нельзя мимоходом — починка немедленно красит гейт задачи, в
|
||||
которой её сделали.
|
||||
- Прогон живого архива (`task verify:archive`) и свёртка под удерживаемой
|
||||
блокировкой (`task verify:busy`) в гейт не входят: минута и около 50 секунд
|
||||
соответственно, плюс данные, которых нет ни на какой другой машине. Гоняет их
|
||||
@@ -158,6 +165,42 @@
|
||||
Запись на каждый воспроизведённый дефект, сразу, а не ретроспективно: со
|
||||
временем теряется не факт, а причина непоймания.
|
||||
|
||||
## 2026-08-04 — правило выбора слоя мерило одно, а отбор шёл по другому [пойман]
|
||||
|
||||
**Что было.** Правило выбора слоя ответа Read API мерило охват **часами
|
||||
объектов**, а ряд отбирался **точной меткой точки**. На периоде короче часа
|
||||
множества расходятся: часовой объект попадает в границы часов запроса, а его
|
||||
единственная точка в период не попадает. Ответ уходил бы пустым при непустых
|
||||
данных соседнего слоя — с непустым `layer`, то есть неотличимо от честной
|
||||
пустоты только по числу точек.
|
||||
|
||||
**Почему поймано.** Профиль `design` на предложении, до кода: и `review-specs`,
|
||||
и `review-rubric` построили один и тот же вход независимо друг от друга
|
||||
(`from = 10:30`, `to = 10:45`). На готовом коде находка стоила бы переписывания
|
||||
выборки; на предложении — абзаца.
|
||||
|
||||
**Что сделано.** Охват меряется метками точек (`first_ts`/`last_ts` уже лежат в
|
||||
покрывающем индексе). Класс промоутнут в
|
||||
`docs/conventions/storage.md` — «предикат выбора источника и предикат отбора
|
||||
данных используют одну границу»: он повторится всюду, где огрубление ради
|
||||
полноты выборки соседствует с точным фильтром.
|
||||
|
||||
## 2026-08-04 — чекпоинт, заведённый ревью, не существовал бы в проде [пойман]
|
||||
|
||||
**Что было.** Враждебный проход построил путь «ответ оборвался по `WriteTimeout`
|
||||
на середине, а `accessLog` написал `200`»: тело в 13 МиБ доехало на 2.7 МиБ,
|
||||
клиент получил нечитаемый JSON, лог сообщил успех. Чекпоинт об обрыве завели —
|
||||
и поставили ему уровень `DEBUG`.
|
||||
|
||||
**Почему поймано.** Эксплуатационный проход прочитал **боевой** конфиг
|
||||
(`config.docker.toml`, `level = "info"`) и показал, что запись уровня `DEBUG`
|
||||
не проходит фильтр `slog` никогда. То есть находка была закрыта наблюдаемостью,
|
||||
которой в проде не существует.
|
||||
|
||||
**Что сделано.** Уровень поднят до `WARN`. Правило, которое из этого следует:
|
||||
**уровень нового чекпоинта сверяется с боевым конфигом, а не с тем, что видно в
|
||||
тестах** — в тестах уровень всегда `DEBUG`.
|
||||
|
||||
Реализованные задачи, находки ревью и решения сюда не пишутся: у них есть
|
||||
коммит, спека и задача. Здесь только промахи конвейера и решения о его составе.
|
||||
|
||||
|
||||
Reference in New Issue
Block a user