- цель parsing-and-storage закрыта по своему критерию; незакрываемый остаток (новые формы от источника, ручные секции задним числом) переехал в тему parsing-completeness - цель mcp поглощена целью read-api, переименованной в «Чтение данных клиентами»: адаптер — последний шаг того же направления, а не своё - read-api-points разложена на конверт с точками, свёртку по сетке и тренировки с записями; спринт 2026-08-04 набран пятью задачами
57 lines
4.4 KiB
Markdown
57 lines
4.4 KiB
Markdown
# Конверт ответа и точки за период
|
|
|
|
- **Секция:** ядро
|
|
- **Зачем:** Точки лежат в витрине и наружу не отдаются: ни один потребитель не может спросить «вес за год» иначе как sqlite3 на хосте
|
|
- **Теги:** goal:read-api
|
|
|
|
Потребитель получает значения метрики за период одним запросом
|
|
`?from&to`, и из ответа видно, что именно ему отдали: слой, род свёртки и
|
|
границу окна, в котором род измерен.
|
|
|
|
Первая из трёх частей, на которые разложена `read-api-points`. Здесь решается
|
|
**конверт** — форма, которую унаследуют все остальные маршруты чтения и оба
|
|
транспорта.
|
|
|
|
**Форма провода решается здесь, один раз.** Сегодня типы `internal/catalog`
|
|
сами несут json-теги, а транспорт владеет только обёрткой: переименование поля
|
|
в домене меняет публичный контракт без касания `httpapi`, и держит это один
|
|
байтовый тест непустого ответа. Либо объявить в `architecture.md`, что типы
|
|
чтения и есть форма провода для всех транспортов (HTTP и MCP отдают её байт в
|
|
байт), либо завести DTO в транспорте. Выбрать надо **до** того, как образец
|
|
скопируют соседние задачи.
|
|
|
|
**Машинерия условного запроса готова — её берут, а не пишут заново.**
|
|
`store.VersionedRead` держит правило «версией, снятой после чтения, не
|
|
подписывать»; `httpapi` умеет `If-None-Match` и `304`. Новое здесь одно: метка
|
|
обязана нести **область действия** — у точек ответ есть функция параметров
|
|
запроса, поэтому `etag(scope, version)` требует их канонизированной формы, иначе
|
|
`304` ответит на другой набор данных. Детали — `docs/architecture.md`,
|
|
«Условный запрос».
|
|
|
|
**Клиент обязан видеть границы окна измерения.** Род метрики измерен по 48 самым
|
|
свежим **общим** часам, а не по последним 48 часам календаря: выключенная
|
|
минутная автоматизация HAE останавливает пополнение множества общих часов, и
|
|
окно замирает, продолжая объявлять род. Единственный след — `last_hour` в
|
|
ответе; конверт обязан его нести.
|
|
|
|
## Критерии приёмки
|
|
|
|
- «вес за год» отвечается одним запросом без доступа к файлу базы — оракул:
|
|
запрос к поднятому сервису на живом архиве
|
|
- в ответе всегда видны `layer`, `aggregation` и `last_hour` — оракул: тест на
|
|
форме ответа
|
|
- повторный запрос с `If-None-Match` даёт `304`, а тот же запрос с другими
|
|
параметрами — `200` с другим телом — оракул: тест на паре запросов с разной
|
|
областью действия метки
|
|
- форма провода объявлена в `docs/architecture.md` — доменные типы или DTO, —
|
|
и соседние маршруты ссылаются на это решение, а не повторяют выбор — оракул:
|
|
глазами по разделу
|
|
|
|
## Рамки
|
|
|
|
Схема не трогается, данные только читаются, сервис перезапускается. Против
|
|
`./data` — только `task up` / `task run`.
|
|
|
|
Связано: `docs/architecture.md` → «Read API», «Условный запрос», «Измерение рода
|
|
агрегации».
|