Files
healthlog/openspec/changes/archive/2026-08-04-tochki-metriki-za-period/proposal.md
T
av 29ca8d415c httpapi: точки метрики за период отдаются одним запросом
- `GET /api/v1/metrics/{name}?from&to&layer` — ряд точек за период; конверт
  объявляет слой, измеренный род, его применимость к отданному ряду и границу
  окна измерения, а сам ряд собирается из одного слоя, выбранного по охвату
  точек внутри периода
- use-case вынесен в `internal/points`, чтение — одним входом `store.ReadSeries`
  под одной транзакцией; правило выбора слоя остаётся в домене и приходит в
  хранилище колбэком
- `writeJSON` перестал экранировать HTML-символы и перестал глушить отказ
  записи: дословность содержимого точки иначе не удерживается, а оборванное
  тело уходило под видом успешного `200`
2026-08-04 18:46:45 +03:00

6.0 KiB

Why

Точки лежат в витрине и наружу не отдаются: «вес за год» достаётся только sqlite3 на хосте. Каталог уже отвечает, что есть, — но ни один из трёх потребителей не может получить сами значения.

Ответ обязан быть самоописательным. Метрика лежит сразу в нескольких слоях подробности, а род её свёртки не объявлен источником, а измерен окном в 48 самых свежих общих часов — окном, которое замирает при выключенной минутной автоматизации HAE и продолжает объявлять род. Клиент, не видящий ни слоя, ни границы этого окна, принимает решение по числу, происхождения которого не знает.

What Changes

  • Новый читающий маршрут GET /api/v1/metrics/{name}?from&to&layer — все точки метрики за период, одним запросом, без доступа к файлу базы.
  • Конверт ответа объявляет фактические параметры выдачи: metric, from, to, layer, bucket, aggregation (род, его применимость к отданному ряду и граница окна измерения), points. Поля присутствуют всегда — клиент не выводит их наличием или отсутствием.
  • Слой выбирается правилом, а не молча: параметр layer задаёт разрез явно, без него берётся слой с наибольшим охватом точек внутри запрошенного периода, при равенстве — самый мелкий. Смены слоя внутри одного ответа не бывает.
  • Род свёртки в конверте — тот же измеренный catalog.Style, что у каталога, и измеряется он тем же правилом и тем же окном. Род неизвестен — так и сказано словом unknown, а не молчанием. Рядом едет применимость: cumulative на нижнем слое HAE объявляется неприменимым, иначе конверт приглашает потребителя сложить интерполяцию и завысить втрое.
  • Свёртка в этом изменении не выполняется: bucket всегда null, а присутствие параметра bucket в запросе отвергается 400, а не игнорируется молча.
  • Ответ снимается одной транзакцией чтения, а метка ответа включает канонизированную форму запроса и горизонт измерения — иначе соседняя задача условного запроса подтвердит 304 на сменившемся роде.
  • Форма провода — по образцу каталога (ADR ADR-2026-08-04-forma-provoda-prinadlezhit-transportu): типы *Wire в internal/httpapi, перевод присваиванием, строка в таблице образцов wire_internal_test.go.

Схема базы не трогается: обе выборки отвечают по существующим ключу и покрывающему индексу bucket_catalog.

Capabilities

New Capabilities

  • points: точки метрики за период — форма запроса и его разбор, правило выбора слоя, состав конверта ответа, объявление измеренного рода вместе с границей окна измерения, дословность значений точки.

Modified Capabilities

  • read-api: добавляются два общих правила читающих маршрутов — сериализация ответа не экранирует содержимое (иначе & внутри дословно сохранённой точки уезжает как &) и ответ чтения помечается непригодным для разделяемого кеша. Оба механизма общие (writeJSON, setReadHeaders), и решать их заново на каждом маршруте — тот же второй способ.

catalog (правило измерения рода) применяется новым маршрутом без изменения его требований.

Impact

  • internal/httpapi — маршрут, разбор параметров, форма провода точек, выключение HTML-экранирования в общем writeJSON.
  • internal/points (новый) — use-case «точки метрики за период»: выбор слоя, сборка ряда, измерение рода и метка ответа по одной метрике.
  • internal/store — один вход чтения ряда (ReadSeries) в одной транзакции: охваты слоёв в периоде, точки выбранного слоя, объекты окна измерения.
  • docs/architecture.md — разделы «Read API» (форма ответа, правило выбора слоя) и таблица компонентов.
  • Потребители: HTTP-клиенты; следом этот же конверт копируют свёртка по сетке, условный запрос по точкам, тренировки, записи и MCP.